summaryrefslogtreecommitdiff
path: root/actions
diff options
context:
space:
mode:
Diffstat (limited to 'actions')
-rw-r--r--actions/accesstoken.php28
-rw-r--r--actions/all.php82
-rw-r--r--actions/allrss.php1
-rw-r--r--actions/api.php293
-rw-r--r--actions/apiaccountratelimitstatus.php112
-rw-r--r--actions/apiaccountverifycredentials.php85
-rw-r--r--actions/apiblockcreate.php114
-rw-r--r--actions/apiblockdestroy.php113
-rw-r--r--actions/apidirectmessage.php375
-rw-r--r--actions/apidirectmessagenew.php188
-rw-r--r--actions/apifavoritecreate.php168
-rw-r--r--actions/apifavoritedestroy.php150
-rw-r--r--actions/apifriendshipscreate.php137
-rw-r--r--actions/apifriendshipsdestroy.php139
-rw-r--r--actions/apifriendshipsexists.php128
-rw-r--r--actions/apifriendshipsshow.php168
-rw-r--r--actions/apigroupcreate.php372
-rw-r--r--actions/apigroupismember.php122
-rw-r--r--actions/apigroupjoin.php163
-rw-r--r--actions/apigroupleave.php149
-rw-r--r--actions/apigrouplist.php223
-rw-r--r--actions/apigrouplistall.php208
-rw-r--r--actions/apigroupmembership.php192
-rw-r--r--actions/apigroupshow.php152
-rw-r--r--actions/apihelptest.php96
-rw-r--r--actions/apistatusesdestroy.php154
-rw-r--r--actions/apistatusesshow.php206
-rw-r--r--actions/apistatusesupdate.php241
-rw-r--r--actions/apistatusnetconfig.php142
-rw-r--r--actions/apistatusnetversion.php102
-rw-r--r--actions/apisubscriptions.php266
-rw-r--r--actions/apitimelinefavorites.php237
-rw-r--r--actions/apitimelinefriends.php247
-rw-r--r--actions/apitimelinegroup.php231
-rw-r--r--actions/apitimelinementions.php233
-rw-r--r--actions/apitimelinepublic.php213
-rw-r--r--actions/apitimelinetag.php224
-rw-r--r--actions/apitimelineuser.php248
-rw-r--r--actions/apiuserfollowers.php89
-rw-r--r--actions/apiuserfriends.php89
-rw-r--r--actions/apiusershow.php126
-rw-r--r--actions/confirmaddress.php6
-rw-r--r--actions/deletenotice.php38
-rw-r--r--actions/doc.php26
-rw-r--r--actions/editgroup.php9
-rw-r--r--actions/favorited.php3
-rw-r--r--actions/favoritesrss.php11
-rw-r--r--actions/finishaddopenid.php185
-rw-r--r--actions/finishopenidlogin.php497
-rw-r--r--actions/finishremotesubscribe.php313
-rw-r--r--actions/foafgroup.php173
-rw-r--r--actions/groupbyid.php5
-rw-r--r--actions/groupdesignsettings.php5
-rw-r--r--actions/grouplogo.php5
-rw-r--r--actions/groupmembers.php9
-rw-r--r--actions/grouprss.php6
-rw-r--r--actions/groupsearch.php3
-rw-r--r--actions/invite.php2
-rw-r--r--actions/joingroup.php5
-rw-r--r--actions/leavegroup.php5
-rw-r--r--actions/login.php11
-rw-r--r--actions/logout.php2
-rw-r--r--actions/newgroup.php9
-rw-r--r--actions/newmessage.php7
-rw-r--r--actions/newnotice.php19
-rw-r--r--actions/noticesearch.php4
-rw-r--r--actions/openidlogin.php139
-rw-r--r--actions/openidsettings.php246
-rw-r--r--actions/othersettings.php27
-rw-r--r--actions/postnotice.php109
-rw-r--r--actions/profilesettings.php14
-rw-r--r--actions/public.php30
-rw-r--r--actions/publicrss.php18
-rw-r--r--actions/publictagcloud.php3
-rw-r--r--actions/publicxrds.php122
-rw-r--r--actions/register.php40
-rw-r--r--actions/remotesubscribe.php336
-rw-r--r--actions/replies.php4
-rw-r--r--actions/repliesrss.php1
-rw-r--r--actions/requesttoken.php21
-rw-r--r--actions/showfavorites.php4
-rw-r--r--actions/showgroup.php17
-rw-r--r--actions/shownotice.php8
-rw-r--r--actions/showstream.php372
-rw-r--r--actions/subscribers.php4
-rw-r--r--actions/twitapiaccount.php127
-rw-r--r--actions/twitapiblocks.php74
-rw-r--r--actions/twitapidirect_messages.php304
-rw-r--r--actions/twitapifavorites.php216
-rw-r--r--actions/twitapifriendships.php250
-rw-r--r--actions/twitapigroups.php329
-rw-r--r--actions/twitapihelp.php57
-rw-r--r--actions/twitapinotifications.php40
-rw-r--r--actions/twitapisearchatom.php8
-rw-r--r--actions/twitapisearchjson.php10
-rw-r--r--actions/twitapistatuses.php604
-rw-r--r--actions/twitapistatusnet.php175
-rw-r--r--actions/twitapitags.php113
-rw-r--r--actions/twitapitrends.php6
-rw-r--r--actions/twitapiusers.php80
-rw-r--r--actions/updateprofile.php202
-rw-r--r--actions/userauthorization.php421
-rw-r--r--actions/userrss.php5
-rw-r--r--actions/xrds.php108
104 files changed, 7655 insertions, 5353 deletions
diff --git a/actions/accesstoken.php b/actions/accesstoken.php
index c99aaeded..76bd40473 100644
--- a/actions/accesstoken.php
+++ b/actions/accesstoken.php
@@ -1,6 +1,6 @@
<?php
/**
- * Access token class.
+ * Access token class
*
* PHP version 5
*
@@ -32,10 +32,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
require_once INSTALLDIR.'/lib/omb.php';
/**
- * Access token class.
+ * Access token class
*
* @category Action
* @package StatusNet
@@ -47,28 +48,23 @@ require_once INSTALLDIR.'/lib/omb.php';
class AccesstokenAction extends Action
{
/**
- * Class handler.
+ * Class handler
*
* @param array $args query arguments
*
- * @return boolean false if user doesn't exist
- */
+ * @return nothing
+ *
+ **/
function handle($args)
{
parent::handle($args);
try {
- common_debug('getting request from env variables', __FILE__);
- common_remove_magic_from_request();
- $req = OAuthRequest::from_request('POST', common_local_url('accesstoken'));
- common_debug('getting a server', __FILE__);
- $server = omb_oauth_server();
- common_debug('fetching the access token', __FILE__);
- $token = $server->fetch_access_token($req);
- common_debug('got this token: "'.print_r($token, true).'"', __FILE__);
- common_debug('printing the access token', __FILE__);
- print $token;
- } catch (OAuthException $e) {
+ $srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
+ omb_oauth_server());
+ $srv->writeAccessToken();
+ } catch (Exception $e) {
$this->serverError($e->getMessage());
}
}
}
+?>
diff --git a/actions/all.php b/actions/all.php
index bfde3a7e4..f1786462e 100644
--- a/actions/all.php
+++ b/actions/all.php
@@ -1,5 +1,5 @@
<?php
-/*
+/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@@ -15,9 +15,25 @@
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Actions
+ * @package Actions
+ * @author Evan Prodromou <evan@status.net>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <millette@controlyourself.ca>
+ * @author Adrian Lang <mail@adrianlang.de>
+ * @author Meitar Moscovitz <meitarm@gmail.com>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@controlyourself.ca>
+ * @license GNU Affero General Public License http://www.gnu.org/licenses/
+ * @link http://status.net
*/
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
require_once INSTALLDIR.'/lib/personalgroupnav.php';
require_once INSTALLDIR.'/lib/noticelist.php';
@@ -43,8 +59,8 @@ class AllAction extends ProfileAction
$this->notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
}
- if($this->page > 1 && $this->notice->N == 0){
- $this->serverError(_('No such page'),$code=404);
+ if ($this->page > 1 && $this->notice->N == 0) {
+ $this->serverError(_('No such page'), $code = 404);
}
return true;
@@ -73,20 +89,33 @@ class AllAction extends ProfileAction
function getFeeds()
{
- return array(new Feed(Feed::RSS1,
- common_local_url('allrss', array('nickname' =>
- $this->user->nickname)),
- sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
- new Feed(Feed::RSS2,
- common_local_url('api', array('apiaction' => 'statuses',
- 'method' => 'friends_timeline',
- 'argument' => $this->user->nickname.'.rss')),
- sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
- new Feed(Feed::ATOM,
- common_local_url('api', array('apiaction' => 'statuses',
- 'method' => 'friends_timeline',
- 'argument' => $this->user->nickname.'.atom')),
- sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)));
+ return array(
+ new Feed(Feed::RSS1,
+ common_local_url(
+ 'allrss', array(
+ 'nickname' =>
+ $this->user->nickname)
+ ),
+ sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
+ new Feed(Feed::RSS2,
+ common_local_url(
+ 'api', array(
+ 'apiaction' => 'statuses',
+ 'method' => 'friends_timeline',
+ 'argument' => $this->user->nickname.'.rss'
+ )
+ ),
+ sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
+ new Feed(Feed::ATOM,
+ common_local_url(
+ 'api', array(
+ 'apiaction' => 'statuses',
+ 'method' => 'friends_timeline',
+ 'argument' => $this->user->nickname.'.atom'
+ )
+ ),
+ sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))
+ );
}
function showLocalNav()
@@ -106,11 +135,8 @@ class AllAction extends ProfileAction
} else {
$message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
}
- }
- 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);
+ } else {
+ $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');
@@ -128,17 +154,19 @@ class AllAction extends ProfileAction
$this->showEmptyListMessage();
}
- $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
- $this->page, 'all', array('nickname' => $this->user->nickname));
+ $this->pagination(
+ $this->page > 1, $cnt > NOTICES_PER_PAGE,
+ $this->page, 'all', array('nickname' => $this->user->nickname)
+ );
}
function showPageTitle()
{
$user =& common_current_user();
if ($user && ($user->id == $this->user->id)) {
- $this->element('h1', NULL, _("You and friends"));
+ $this->element('h1', null, _("You and friends"));
} else {
- $this->element('h1', NULL, sprintf(_('%s and friends'), $this->user->nickname));
+ $this->element('h1', null, sprintf(_('%s and friends'), $this->user->nickname));
}
}
diff --git a/actions/allrss.php b/actions/allrss.php
index 57efb73f0..28b1be27d 100644
--- a/actions/allrss.php
+++ b/actions/allrss.php
@@ -68,6 +68,7 @@ class AllrssAction extends Rss10Action
$this->clientError(_('No such user.'));
return false;
} else {
+ $this->notices = $this->getNotices($this->limit);
return true;
}
}
diff --git a/actions/api.php b/actions/api.php
deleted file mode 100644
index 3705d035c..000000000
--- a/actions/api.php
+++ /dev/null
@@ -1,293 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-class ApiAction extends Action
-{
-
- var $user;
- var $content_type;
- var $api_arg;
- var $api_method;
- var $api_action;
- var $auth_user;
- var $auth_pw;
-
- function handle($args)
- {
- parent::handle($args);
-
- $this->api_action = $this->arg('apiaction');
- $method = $this->arg('method');
- $argument = $this->arg('argument');
- $this->basic_auth_process_header();
-
- if (isset($argument)) {
- $cmdext = explode('.', $argument);
- $this->api_arg = $cmdext[0];
- $this->api_method = $method;
- $this->content_type = strtolower($cmdext[1]);
- } else {
-
- # Requested format / content-type will be an extension on the method
- $cmdext = explode('.', $method);
- $this->api_method = $cmdext[0];
- $this->content_type = strtolower($cmdext[1]);
- }
-
- if ($this->requires_auth()) {
- if (!isset($this->auth_user)) {
-
- # This header makes basic auth go
- header('WWW-Authenticate: Basic realm="StatusNet API"');
-
- # If the user hits cancel -- bam!
- $this->show_basic_auth_error();
- } else {
- $nickname = $this->auth_user;
- $password = $this->auth_pw;
- $user = common_check_user($nickname, $password);
-
- if ($user) {
- $this->user = $user;
- $this->process_command();
- } else {
- # basic authentication failed
- list($proxy, $ip) = common_client_ip();
-
- common_log(LOG_WARNING, "Failed API auth attempt, nickname = $nickname, proxy = $proxy, ip = $ip.");
- $this->show_basic_auth_error();
- }
- }
- } else {
-
- // Caller might give us a username even if not required
- if (isset($this->auth_user)) {
- $user = User::staticGet('nickname', $this->auth_user);
- if ($user) {
- $this->user = $user;
- }
- # Twitter doesn't throw an error if the user isn't found
- }
-
- $this->process_command();
- }
- }
-
- function process_command()
- {
- $action = "twitapi$this->api_action";
- $actionfile = INSTALLDIR."/actions/$action.php";
-
- if (file_exists($actionfile)) {
- require_once($actionfile);
- $action_class = ucfirst($action)."Action";
- $action_obj = new $action_class();
-
- if (!$action_obj->prepare($this->args)) {
- return;
- }
-
- if (method_exists($action_obj, $this->api_method)) {
- $apidata = array( 'content-type' => $this->content_type,
- 'api_method' => $this->api_method,
- 'api_arg' => $this->api_arg,
- 'user' => $this->user);
-
- call_user_func(array($action_obj, $this->api_method), $_REQUEST, $apidata);
- } else {
- $this->clientError("API method not found!", $code=404);
- }
- } else {
- $this->clientError("API method not found!", $code=404);
- }
- }
-
- // Whitelist of API methods that don't need authentication
- function requires_auth()
- {
- static $noauth = array( 'statuses/public_timeline',
- 'statuses/show',
- 'users/show',
- 'help/test',
- 'help/downtime_schedule',
- 'statusnet/version',
- 'statusnet/config',
- 'statusnet/wadl',
- 'tags/timeline',
- 'oembed/oembed',
- 'groups/show',
- 'groups/timeline',
- 'groups/list_all',
- 'groups/membership',
- 'groups/is_member',
- 'groups/timeline');
-
- static $bareauth = array('statuses/user_timeline',
- 'statuses/friends_timeline',
- 'statuses/home_timeline',
- 'statuses/friends',
- 'statuses/replies',
- 'statuses/mentions',
- 'statuses/followers',
- 'favorites/favorites',
- 'friendships/show',
- 'groups/list_groups');
-
- $fullname = "$this->api_action/$this->api_method";
-
- // If the site is "private", all API methods except statusnet/config
- // need authentication
-
- if (common_config('site', 'private')) {
- return $fullname != 'statusnet/config' || false;
- }
-
- // bareauth: only needs auth if without an argument or query param specifying user
-
- if (in_array($fullname, $bareauth)) {
-
- // Special case: friendships/show only needs auth if source_id or
- // source_screen_name is not specified as a param
-
- if ($fullname == 'friendships/show') {
-
- $source_id = $this->arg('source_id');
- $source_screen_name = $this->arg('source_screen_name');
-
- if (empty($source_id) && empty($source_screen_name)) {
- return true;
- }
-
- return false;
- }
-
- // if all of these are empty, auth is required
-
- $id = $this->arg('id');
- $user_id = $this->arg('user_id');
- $screen_name = $this->arg('screen_name');
-
- if (empty($this->api_arg) &&
- empty($id) &&
- empty($user_id) &&
- empty($screen_name)) {
- return true;
- } else {
- return false;
- }
-
- } else if (in_array($fullname, $noauth)) {
-
- // noauth: never needs auth
-
- return false;
- } else {
-
- // everybody else needs auth
-
- return true;
- }
- }
-
- function basic_auth_process_header()
- {
- if(isset($_SERVER['AUTHORIZATION']) || isset($_SERVER['HTTP_AUTHORIZATION']))
- {
- $authorization_header = isset($_SERVER['HTTP_AUTHORIZATION'])?$_SERVER['HTTP_AUTHORIZATION']:$_SERVER['AUTHORIZATION'];
- }
-
- if(isset($_SERVER['PHP_AUTH_USER']))
- {
- $this->auth_user = $_SERVER['PHP_AUTH_USER'];
- $this->auth_pw = $_SERVER['PHP_AUTH_PW'];
- }
- elseif ( isset($authorization_header) && strstr(substr($authorization_header, 0,5),'Basic') )
- {
- // decode the HTTP_AUTHORIZATION header on php-cgi server self
- // on fcgid server the header name is AUTHORIZATION
-
- $auth_hash = base64_decode( substr($authorization_header, 6) );
- list($this->auth_user, $this->auth_pw) = explode(':', $auth_hash);
-
- // set all to NULL on a empty basic auth request
- if($this->auth_user == "") {
- $this->auth_user = NULL;
- $this->auth_pw = NULL;
- }
- }
- else
- {
- $this->auth_user = NULL;
- $this->auth_pw = NULL;
- }
- }
-
- function show_basic_auth_error()
- {
- header('HTTP/1.1 401 Unauthorized');
- $msg = 'Could not authenticate you.';
-
- if ($this->content_type == 'xml') {
- header('Content-Type: application/xml; charset=utf-8');
- $this->startXML();
- $this->elementStart('hash');
- $this->element('error', null, $msg);
- $this->element('request', null, $_SERVER['REQUEST_URI']);
- $this->elementEnd('hash');
- $this->endXML();
- } else if ($this->content_type == 'json') {
- header('Content-Type: application/json; charset=utf-8');
- $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
- print(json_encode($error_array));
- } else {
- header('Content-type: text/plain');
- print "$msg\n";
- }
- }
-
- function isReadOnly($args)
- {
- $apiaction = $args['apiaction'];
- $method = $args['method'];
-
- list($cmdtext, $fmt) = explode('.', $method);
-
- static $write_methods = array(
- 'account' => array('update_location', 'update_delivery_device', 'end_session'),
- 'blocks' => array('create', 'destroy'),
- 'direct_messages' => array('create', 'destroy'),
- 'favorites' => array('create', 'destroy'),
- 'friendships' => array('create', 'destroy'),
- 'help' => array(),
- 'notifications' => array('follow', 'leave'),
- 'statuses' => array('update', 'destroy'),
- 'users' => array()
- );
-
- if (array_key_exists($apiaction, $write_methods)) {
- if (!in_array($cmdtext, $write_methods[$apiaction])) {
- return true;
- }
- }
-
- return false;
- }
-}
diff --git a/actions/apiaccountratelimitstatus.php b/actions/apiaccountratelimitstatus.php
new file mode 100644
index 000000000..96179f175
--- /dev/null
+++ b/actions/apiaccountratelimitstatus.php
@@ -0,0 +1,112 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Dummy action that emulates Twitter's rate limit status API resource
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * We don't have a rate limit, but some clients check this method.
+ * It always returns the same thing: 150 hits left.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiAccountRateLimitStatusAction extends ApiBareAuthAction
+{
+
+ /**
+ * Handle the request
+ *
+ * Return some Twitter-ish data about API limits
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ $reset = new DateTime();
+ $reset->modify('+1 hour');
+
+ $this->initDocument($this->format);
+
+ if ($this->format == 'xml') {
+ $this->elementStart('hash');
+ $this->element('remaining-hits', array('type' => 'integer'), 150);
+ $this->element('hourly-limit', array('type' => 'integer'), 150);
+ $this->element(
+ 'reset-time', array('type' => 'datetime'),
+ common_date_iso8601($reset->format('r'))
+ );
+ $this->element(
+ 'reset_time_in_seconds',
+ array('type' => 'integer'),
+ strtotime('+1 hour')
+ );
+ $this->elementEnd('hash');
+ } elseif ($this->format == 'json') {
+ $out = array(
+ 'reset_time_in_seconds' => strtotime('+1 hour'),
+ 'remaining_hits' => 150,
+ 'hourly_limit' => 150,
+ 'reset_time' => common_date_rfc2822(
+ $reset->format('r')
+ )
+ );
+ print json_encode($out);
+ }
+
+ $this->endDocument($this->format);
+ }
+
+}
+
diff --git a/actions/apiaccountverifycredentials.php b/actions/apiaccountverifycredentials.php
new file mode 100644
index 000000000..08b201dbf
--- /dev/null
+++ b/actions/apiaccountverifycredentials.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Test if supplied user credentials are valid.
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Check a user's credentials. Returns an HTTP 200 OK response code and a
+ * representation of the requesting user if authentication was successful;
+ * returns a 401 status code and an error message if not.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiAccountVerifyCredentialsAction extends ApiAuthAction
+{
+
+ /**
+ * Handle the request
+ *
+ * Check whether the credentials are valid and output the result
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ switch ($this->format) {
+ case 'xml':
+ case 'json':
+ $args['id'] = $this->auth_user->id;
+ $action_obj = new ApiUserShowAction();
+ if ($action_obj->prepare($args)) {
+ $action_obj->handle($args);
+ }
+ break;
+ default:
+ header('Content-Type: text/html; charset=utf-8');
+ print 'Authorized';
+ }
+
+ }
+
+}
diff --git a/actions/apiblockcreate.php b/actions/apiblockcreate.php
new file mode 100644
index 000000000..1cab2df5d
--- /dev/null
+++ b/actions/apiblockcreate.php
@@ -0,0 +1,114 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Block a user via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Blocks the user specified in the ID parameter as the authenticating user.
+ * Destroys a friendship to the blocked user if it exists. Returns the
+ * blocked user in the requested format when successful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiBlockCreateAction extends ApiAuthAction
+{
+ var $other = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->other = $this->getTargetUser($this->arg('id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Save the new message
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->user) || empty($this->other)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ if ($this->user->hasBlocked($this->other)
+ || $this->user->block($this->other)
+ ) {
+ $this->initDocument($this->format);
+ $this->showProfile($this->other, $this->format);
+ $this->endDocument($this->format);
+ } else {
+ $this->serverError(_('Block user failed.'), 500, $this->format);
+ }
+
+ }
+
+}
+
diff --git a/actions/apiblockdestroy.php b/actions/apiblockdestroy.php
new file mode 100644
index 000000000..16dbf94ca
--- /dev/null
+++ b/actions/apiblockdestroy.php
@@ -0,0 +1,113 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Un-block a user via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Un-blocks the user specified in the ID parameter for the authenticating user.
+ * Returns the un-blocked user in the requested format when successful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiBlockDestroyAction extends ApiAuthAction
+{
+ var $other = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->other = $this->getTargetUser($this->arg('id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Save the new message
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->user) || empty($this->other)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ if (!$this->user->hasBlocked($this->other)
+ || $this->user->unblock($this->other)
+ ) {
+ $this->initDocument($this->format);
+ $this->showProfile($this->other, $this->format);
+ $this->endDocument($this->format);
+ } else {
+ $this->serverError(_('Unblock user failed.'));
+ }
+
+ }
+
+}
+
diff --git a/actions/apidirectmessage.php b/actions/apidirectmessage.php
new file mode 100644
index 000000000..a21fe86d2
--- /dev/null
+++ b/actions/apidirectmessage.php
@@ -0,0 +1,375 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a the direct messages from or to a user
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Adrian Lang <mail@adrianlang.de>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Show a list of direct messages from or to the authenticating user
+ *
+ * @category API
+ * @package StatusNet
+ * @author Adrian Lang <mail@adrianlang.de>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiDirectMessageAction extends ApiAuthAction
+{
+ var $messages = null;
+ var $title = null;
+ var $subtitle = null;
+ var $link = null;
+ var $selfuri_base = null;
+ var $id = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ $server = common_root_url();
+ $taguribase = common_config('integration', 'taguri');
+
+ if ($this->arg('sent')) {
+
+ // Action was called by /api/direct_messages/sent.format
+
+ $this->title = sprintf(
+ _("Direct messages from %s"),
+ $this->user->nickname
+ );
+ $this->subtitle = sprintf(
+ _("All the direct messages sent from %s"),
+ $this->user->nickname
+ );
+ $this->link = $server . $this->user->nickname . '/outbox';
+ $this->selfuri_base = common_root_url() . 'api/direct_messages/sent';
+ $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id;
+ } else {
+ $this->title = sprintf(
+ _("Direct messages to %s"),
+ $this->user->nickname
+ );
+ $this->subtitle = sprintf(
+ _("All the direct messages sent to %s"),
+ $this->user->nickname
+ );
+ $this->link = $server . $this->user->nickname . '/inbox';
+ $this->selfuri_base = common_root_url() . 'api/direct_messages';
+ $this->id = "tag:$taguribase:DirectMessages:" . $this->user->id;
+ }
+
+ $this->messages = $this->getMessages();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Show the messages
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showMessages();
+ }
+
+ /**
+ * Show the messages
+ *
+ * @return void
+ */
+
+ function showMessages()
+ {
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlDirectMessages();
+ break;
+ case 'rss':
+ $this->showRssDirectMessages();
+ break;
+ case 'atom':
+ $this->showAtomDirectMessages();
+ break;
+ case 'json':
+ $this->showJsonDirectMessages();
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getMessages()
+ {
+ $message = new Message();
+
+ if ($this->arg('sent')) {
+ $message->from_profile = $this->user->id;
+ } else {
+ $message->to_profile = $this->user->id;
+ }
+
+ if (!empty($this->max_id)) {
+ $message->whereAdd('id <= ' . $this->max_id);
+ }
+
+ if (!empty($this->since_id)) {
+ $message->whereAdd('id > ' . $this->since_id);
+ }
+
+ if (!empty($since)) {
+ $d = date('Y-m-d H:i:s', $this->since);
+ $message->whereAdd("created > '$d'");
+ }
+
+ $message->orderBy('created DESC, id DESC');
+ $message->limit((($this->page - 1) * $this->count), $this->count);
+ $message->find();
+
+ $messages = array();
+
+ while ($message->fetch()) {
+ $messages[] = clone($message);
+ }
+
+ return $messages;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this notice last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->messages)) {
+ return strtotime($this->messages[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * Shows a list of direct messages as Twitter-style XML array
+ *
+ * @return void
+ */
+
+ function showXmlDirectMessages()
+ {
+ $this->initDocument('xml');
+ $this->elementStart('direct-messages', array('type' => 'array'));
+
+ foreach ($this->messages as $m) {
+ $dm_array = $this->directMessageArray($m);
+ $this->showXmlDirectMessage($dm_array);
+ }
+
+ $this->elementEnd('direct-messages');
+ $this->endDocument('xml');
+ }
+
+ /**
+ * Shows a list of direct messages as a JSON encoded array
+ *
+ * @return void
+ */
+
+ function showJsonDirectMessages()
+ {
+ $this->initDocument('json');
+
+ $dmsgs = array();
+
+ foreach ($this->messages as $m) {
+ $dm_array = $this->directMessageArray($m);
+ array_push($dmsgs, $dm_array);
+ }
+
+ $this->showJsonObjects($dmsgs);
+ $this->endDocument('json');
+ }
+
+ /**
+ * Shows a list of direct messages as RSS items
+ *
+ * @return void
+ */
+
+ function showRssDirectMessages()
+ {
+ $this->initDocument('rss');
+
+ $this->element('title', null, $this->title);
+
+ $this->element('link', null, $this->link);
+ $this->element('description', null, $this->subtitle);
+ $this->element('language', null, 'en-us');
+
+ $this->element(
+ 'atom:link',
+ array(
+ 'type' => 'application/rss+xml',
+ 'href' => $this->selfuri_base . '.rss',
+ 'rel' => self
+ ),
+ null
+ );
+ $this->element('ttl', null, '40');
+
+ foreach ($this->messages as $m) {
+ $entry = $this->rssDirectMessageArray($m);
+ $this->showTwitterRssItem($entry);
+ }
+
+ $this->endTwitterRss();
+ }
+
+ /**
+ * Shows a list of direct messages as Atom entries
+ *
+ * @return void
+ */
+
+ function showAtomDirectMessages()
+ {
+ $this->initDocument('atom');
+
+ $this->element('title', null, $this->title);
+ $this->element('id', null, $this->id);
+
+ $selfuri = common_root_url() . 'api/direct_messages.atom';
+
+ $this->element(
+ 'link', array(
+ 'href' => $this->link,
+ 'rel' => 'alternate',
+ 'type' => 'text/html'),
+ null
+ );
+ $this->element(
+ 'link', array(
+ 'href' => $this->selfuri_base . '.atom', 'rel' => 'self',
+ 'type' => 'application/atom+xml'),
+ null
+ );
+ $this->element('updated', null, common_date_iso8601('now'));
+ $this->element('subtitle', null, $this->subtitle);
+
+ foreach ($this->messages as $m) {
+ $entry = $this->rssDirectMessageArray($m);
+ $this->showTwitterAtomEntry($entry);
+ }
+
+ $this->endDocument('atom');
+ }
+
+ /**
+ * An entity tag for this notice
+ *
+ * Returns an Etag based on the action name, language, and
+ * timestamps of the notice
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->messages)) {
+
+ $last = count($this->messages) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ strtotime($this->messages[0]->created),
+ strtotime($this->messages[$last]->created)
+ )
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php
new file mode 100644
index 000000000..ca1ee70dd
--- /dev/null
+++ b/actions/apidirectmessagenew.php
@@ -0,0 +1,188 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Send a direct message via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Adrian Lang <mail@adrianlang.de>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Creates a new direct message from the authenticating user to
+ * the user specified by id.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Adrian Lang <mail@adrianlang.de>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiDirectMessageNewAction extends ApiAuthAction
+{
+ var $source = null;
+ var $other = null;
+ var $content = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ $this->source = $this->trimmed('source'); // Not supported by Twitter.
+
+ $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
+ if (empty($thtis->source) || in_array($this->source, $reserved_sources)) {
+ $source = 'api';
+ }
+
+ $this->content = $this->trimmed('text');
+
+ $this->user = $this->auth_user;
+
+ $user_param = $this->trimmed('user');
+ $user_id = $this->arg('user_id');
+ $screen_name = $this->trimmed('screen_name');
+
+ if (isset($user_param) || isset($user_id) || isset($screen_name)) {
+ $this->other = $this->getTargetUser($user_param);
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Save the new message
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->content)) {
+ $this->clientError(
+ _('No message text!'),
+ 406,
+ $this->format
+ );
+ } else {
+ $content_shortened = common_shorten_links($this->content);
+ if (Message::contentTooLong($content_shortened)) {
+ $this->clientError(
+ sprintf(
+ _('That\'s too long. Max message size is %d chars.'),
+ Message::maxContent()
+ ),
+ 406,
+ $this->format
+ );
+ return;
+ }
+ }
+
+ if (empty($this->other)) {
+ $this->clientError(_('Recipient user not found.'), 403, $this->format);
+ return;
+ } else if (!$this->user->mutuallySubscribed($this->other)) {
+ $this->clientError(
+ _('Can\'t send direct messages to users who aren\'t your friend.'),
+ 403,
+ $this->format
+ );
+ return;
+ } else if ($this->user->id == $this->other->id) {
+
+ // Note: sending msgs to yourself is allowed by Twitter
+
+ $errmsg = 'Don\'t send a message to yourself; ' .
+ 'just say it to yourself quietly instead.';
+
+ $this->clientError(_($errmsg), 403, $this->format);
+ return;
+ }
+
+ $message = Message::saveNew(
+ $this->user->id,
+ $this->other->id,
+ html_entity_decode($this->content, ENT_NOQUOTES, 'UTF-8'),
+ $this->source
+ );
+
+ if (is_string($message)) {
+ $this->serverError($message);
+ return;
+ }
+
+ mail_notify_message($message, $this->user, $this->other);
+
+ if ($this->format == 'xml') {
+ $this->showSingleXmlDirectMessage($message);
+ } elseif ($this->format == 'json') {
+ $this->showSingleJsondirectMessage($message);
+ }
+ }
+
+}
+
diff --git a/actions/apifavoritecreate.php b/actions/apifavoritecreate.php
new file mode 100644
index 000000000..436739770
--- /dev/null
+++ b/actions/apifavoritecreate.php
@@ -0,0 +1,168 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Add a notice to a user's list of favorite notices via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Favorites the status specified in the ID parameter as the authenticating user.
+ * Returns the favorite status when successful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiFavoriteCreateAction extends ApiAuthAction
+{
+ var $notice = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->notice = Notice::staticGet($this->arg('id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->notice)) {
+ $this->clientError(
+ _('No status found with that ID.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ // Note: Twitter lets you fave things repeatedly via API.
+
+ if ($this->user->hasFave($this->notice)) {
+ $this->clientError(
+ _('This status is already a favorite!'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ $fave = Fave::addNew($this->user, $this->notice);
+
+ if (empty($fave)) {
+ $this->clientError(
+ _('Could not create favorite.'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ $this->notify($fave, $this->notice, $this->user);
+ $this->user->blowFavesCache();
+
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ }
+
+ /**
+ * Notify the author of the favorite that the user likes their notice
+ *
+ * @param Favorite $fave the favorite in question
+ * @param Notice $notice the notice that's been faved
+ * @param User $user the user doing the favoriting
+ *
+ * @return void
+ */
+ function notify($fave, $notice, $user)
+ {
+ $other = User::staticGet('id', $notice->profile_id);
+ if ($other && $other->id != $user->id) {
+ if ($other->email && $other->emailnotifyfav) {
+ mail_notify_fave($other, $user, $notice);
+ }
+ // XXX: notify by IM
+ // XXX: notify by SMS
+ }
+ }
+
+}
diff --git a/actions/apifavoritedestroy.php b/actions/apifavoritedestroy.php
new file mode 100644
index 000000000..f131d1c7f
--- /dev/null
+++ b/actions/apifavoritedestroy.php
@@ -0,0 +1,150 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Remote a notice from a user's list of favorite notices via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Un-favorites the status specified in the ID parameter as the authenticating user.
+ * Returns the un-favorited status in the requested format when successful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiFavoriteDestroyAction extends ApiAuthAction
+{
+
+ var $notice = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->notice = Notice::staticGet($this->arg('id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->notice)) {
+ $this->clientError(
+ _('No status found with that ID.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ $fave = new Fave();
+ $fave->user_id = $this->user->id;
+ $fave->notice_id = $this->notice->id;
+
+ if (!$fave->find(true)) {
+ $this->clientError(
+ _('That status is not a favorite!'),
+ 403,
+ $this->favorite
+ );
+ return;
+ }
+
+ $result = $fave->delete();
+
+ if (!$result) {
+ common_log_db_error($fave, 'DELETE', __FILE__);
+ $this->clientError(
+ _('Could not delete favorite.'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ $this->user->blowFavesCache();
+
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ }
+
+}
diff --git a/actions/apifriendshipscreate.php b/actions/apifriendshipscreate.php
new file mode 100644
index 000000000..a824e734b
--- /dev/null
+++ b/actions/apifriendshipscreate.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Subscribe to a user via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Allows the authenticating users to follow (subscribe) the user specified in
+ * the ID parameter. Returns the befriended user in the requested format when
+ * successful. Returns a string describing the failure condition when unsuccessful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiFriendshipsCreateAction extends ApiAuthAction
+{
+ var $other = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->other = $this->getTargetUser($id);
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->other)) {
+ $this->clientError(
+ _('Could not follow user: User not found.'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ if ($this->user->isSubscribed($this->other)) {
+ $errmsg = sprintf(
+ _('Could not follow user: %s is already on your list.'),
+ $this->other->nickname
+ );
+ $this->clientError($errmsg, 403, $this->format);
+ return;
+ }
+
+ $result = subs_subscribe_to($this->user, $this->other);
+
+ if (is_string($result)) {
+ $this->clientError($result, 403, $this->format);
+ return;
+ }
+
+ $this->initDocument($this->format);
+ $this->showProfile($this->other, $this->format);
+ $this->endDocument($this->format);
+ }
+
+}
diff --git a/actions/apifriendshipsdestroy.php b/actions/apifriendshipsdestroy.php
new file mode 100644
index 000000000..3d9b7e001
--- /dev/null
+++ b/actions/apifriendshipsdestroy.php
@@ -0,0 +1,139 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Unsubscribe to a user via API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Allows the authenticating users to unfollow (unsubscribe) the user specified in
+ * the ID parameter. Returns the unfollowed user in the requested format when
+ * successful. Returns a string describing the failure condition when unsuccessful.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiFriendshipsDestroyAction extends ApiAuthAction
+{
+ var $other = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->other = $this->getTargetUser($id);
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->other)) {
+ $this->clientError(
+ _('Could not unfollow user: User not found.'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ // Don't allow unsubscribing from yourself!
+
+ if ($this->user->id == $this->other->id) {
+ $this->clientError(
+ _("You cannot unfollow yourself!"),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ $result = subs_unsubscribe_user($this->user, $this->other->nickname);
+
+ if (is_string($result)) {
+ $this->clientError($result, 403, $this->format);
+ return;
+ }
+
+ $this->initDocument($this->format);
+ $this->showProfile($this->other, $this->format);
+ $this->endDocument($this->format);
+ }
+
+}
diff --git a/actions/apifriendshipsexists.php b/actions/apifriendshipsexists.php
new file mode 100644
index 000000000..ae50c512c
--- /dev/null
+++ b/actions/apifriendshipsexists.php
@@ -0,0 +1,128 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show whether there is a friendship between two users
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Tests for the existence of friendship between two users. Will return true if
+ * user_a follows user_b, otherwise will return false.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiFriendshipsExistsAction extends ApiAction
+{
+ var $user_a = null;
+ var $user_b = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $user_a_id = $this->trimmed('user_a');
+ $user_b_id = $this->trimmed('user_b');
+
+ common_debug("user_a = " . $user_a_id);
+ common_debug("user_b = " . $user_b_id);
+
+
+ $this->user_a = $this->getTargetUser($user_a_id);
+
+ if (empty($this->user_a)) {
+ common_debug('gargargra');
+ }
+
+ $this->user_b = $this->getTargetUser($user_b_id);
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (empty($this->user_a) || empty($this->user_b)) {
+ $this->clientError(
+ _('Two user ids or screen_names must be supplied.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ $result = $this->user_a->isSubscribed($this->user_b);
+
+ switch ($this->format) {
+ case 'xml':
+ $this->initDocument('xml');
+ $this->element('friends', null, $result);
+ $this->endDocument('xml');
+ break;
+ case 'json':
+ $this->initDocument('json');
+ print json_encode($result);
+ $this->endDocument('json');
+ break;
+ default:
+ break;
+ }
+ }
+
+}
diff --git a/actions/apifriendshipsshow.php b/actions/apifriendshipsshow.php
new file mode 100644
index 000000000..8fc436738
--- /dev/null
+++ b/actions/apifriendshipsshow.php
@@ -0,0 +1,168 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show information about the relationship between two users
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Outputs detailed information about the relationship between two users
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiFriendshipsShowAction extends ApiBareAuthAction
+{
+ var $source = null;
+ var $target = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $source_id = (int)$this->trimmed('source_id');
+ $source_screen_name = $this->trimmed('source_screen_name');
+ $target_id = (int)$this->trimmed('target_id');
+ $target_screen_name = $this->trimmed('target_screen_name');
+
+ if (!empty($source_id)) {
+ $this->source = User::staticGet($source_id);
+ } elseif (!empty($source_screen_name)) {
+ $this->source = User::staticGet('nickname', $source_screen_name);
+ } else {
+ $this->source = $this->auth_user;
+ }
+
+ if (!empty($target_id)) {
+ $this->target = User::staticGet($target_id);
+ } elseif (!empty($target_screen_name)) {
+ $this->target = User::staticGet('nickname', $target_screen_name);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Determines whether this API resource requires auth. Overloaded to look
+ * return true in case source_id and source_screen_name are both empty
+ *
+ * @return boolean true or false
+ */
+
+ function requiresAuth()
+ {
+ if (common_config('site', 'private')) {
+ return true;
+ }
+
+ $source_id = $this->trimmed('source_id');
+ $source_screen_name = $this->trimmed('source_screen_name');
+
+ if (empty($source_id) && empty($source_screen_name)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(_('API method not found!'), 404);
+ return;
+ }
+
+ if (empty($this->source)) {
+ $this->clientError(
+ _('Could not determine source user.'),
+ 404
+ );
+ return;
+ }
+
+ if (empty($this->target)) {
+ $this->clientError(
+ _('Could not find target user.'),
+ 404
+ );
+ return;
+ }
+
+ $result = $this->twitterRelationshipArray($this->source, $this->target);
+
+ switch ($this->format) {
+ case 'xml':
+ $this->initDocument('xml');
+ $this->showTwitterXmlRelationship($result[relationship]);
+ $this->endDocument('xml');
+ break;
+ case 'json':
+ $this->initDocument('json');
+ print json_encode($result);
+ $this->endDocument('json');
+ break;
+ default:
+ break;
+ }
+
+ }
+
+}
diff --git a/actions/apigroupcreate.php b/actions/apigroupcreate.php
new file mode 100644
index 000000000..f66e83073
--- /dev/null
+++ b/actions/apigroupcreate.php
@@ -0,0 +1,372 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Create a group via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Make a new group. Sets the authenticated user as the administrator of the group.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupCreateAction extends ApiAuthAction
+{
+ var $group = null;
+ var $nickname = null;
+ var $fullname = null;
+ var $homepage = null;
+ var $description = null;
+ var $location = null;
+ var $aliasstring = null;
+ var $aliases = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+
+ $this->nickname = $this->arg('nickname');
+ $this->fullname = $this->arg('full_name');
+ $this->homepage = $this->arg('homepage');
+ $this->description = $this->arg('description');
+ $this->location = $this->arg('location');
+ $this->aliasstring = $this->arg('aliases');
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Save the new group
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ if ($this->validateParams() == false) {
+ return;
+ }
+
+ $group = new User_group();
+
+ $group->query('BEGIN');
+
+ $group->nickname = $this->nickname;
+ $group->fullname = $this->fullname;
+ $group->homepage = $this->homepage;
+ $group->description = $this->description;
+ $group->location = $this->location;
+ $group->created = common_sql_now();
+
+ $result = $group->insert();
+
+ if (!$result) {
+ common_log_db_error($group, 'INSERT', __FILE__);
+ $this->serverError(
+ _('Could not create group.'),
+ 500,
+ $this->format
+ );
+ return;
+ }
+
+ $result = $group->setAliases($this->aliases);
+
+ if (!$result) {
+ $this->serverError(
+ _('Could not create aliases.'),
+ 500,
+ $this->format
+ );
+ return;
+ }
+
+ $member = new Group_member();
+
+ $member->group_id = $group->id;
+ $member->profile_id = $this->user->id;
+ $member->is_admin = 1;
+ $member->created = $group->created;
+
+ $result = $member->insert();
+
+ if (!$result) {
+ common_log_db_error($member, 'INSERT', __FILE__);
+ $this->serverError(
+ _('Could not set group membership.'),
+ 500,
+ $this->format
+ );
+ return;
+ }
+
+ $group->query('COMMIT');
+
+ switch($this->format) {
+ case 'xml':
+ $this->showSingleXmlGroup($group);
+ break;
+ case 'json':
+ $this->showSingleJsonGroup($group);
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+
+ }
+
+ /**
+ * Validate params for the new group
+ *
+ * @return void
+ */
+
+ function validateParams()
+ {
+ $valid = Validate::string(
+ $this->nickname, array(
+ 'min_length' => 1,
+ 'max_length' => 64,
+ 'format' => NICKNAME_FMT
+ )
+ );
+
+ if (!$valid) {
+ $this->clientError(
+ _(
+ 'Nickname must have only lowercase letters ' .
+ 'and numbers and no spaces.'
+ ),
+ 403,
+ $this->format
+ );
+ return false;
+ } elseif ($this->groupNicknameExists($this->nickname)) {
+ $this->clientError(
+ _('Nickname already in use. Try another one.'),
+ 403,
+ $this->format
+ );
+ return false;
+ } else if (!User_group::allowedNickname($this->nickname)) {
+ $this->clientError(
+ _('Not a valid nickname.'),
+ 403,
+ $this->format
+ );
+ return false;
+
+ } elseif (
+ !is_null($this->homepage)
+ && strlen($this->homepage) > 0
+ && !Validate::uri(
+ $this->homepage, array(
+ 'allowed_schemes' =>
+ array('http', 'https')
+ )
+ )) {
+ $this->clientError(
+ _('Homepage is not a valid URL.'),
+ 403,
+ $this->format
+ );
+ return false;
+ } elseif (
+ !is_null($this->fullname)
+ && mb_strlen($this->fullname) > 255) {
+ $this->clientError(
+ _('Full name is too long (max 255 chars).'),
+ 403,
+ $this->format
+ );
+ return false;
+ } elseif (User_group::descriptionTooLong($this->description)) {
+ $this->clientError(
+ sprintf(
+ _('Description is too long (max %d chars).'),
+ User_group::maxDescription()
+ ),
+ 403,
+ $this->format
+ );
+ return false;
+ } elseif (
+ !is_null($this->location)
+ && mb_strlen($this->location) > 255) {
+ $this->clientError(
+ _('Location is too long (max 255 chars).'),
+ 403,
+ $this->format
+ );
+ return false;
+ }
+
+ if (!empty($this->aliasstring)) {
+ $this->aliases = array_map(
+ 'common_canonical_nickname',
+ array_unique(preg_split('/[\s,]+/', $this->aliasstring))
+ );
+ } else {
+ $this->aliases = array();
+ }
+
+ if (count($this->aliases) > common_config('group', 'maxaliases')) {
+ $this->clientError(
+ sprintf(
+ _('Too many aliases! Maximum %d.'),
+ common_config('group', 'maxaliases')
+ ),
+ 403,
+ $this->format
+ );
+ return false;
+ }
+
+ foreach ($this->aliases as $alias) {
+
+ $valid = Validate::string(
+ $alias, array(
+ 'min_length' => 1,
+ 'max_length' => 64,
+ 'format' => NICKNAME_FMT
+ )
+ );
+
+ if (!$valid) {
+ $this->clientError(
+ sprintf(_('Invalid alias: "%s"'), $alias),
+ 403,
+ $this->format
+ );
+ return false;
+ }
+ if ($this->groupNicknameExists($alias)) {
+ $this->clientError(
+ sprintf(
+ _('Alias "%s" already in use. Try another one.'),
+ $alias
+ ),
+ 403,
+ $this->format
+ );
+ return false;
+ }
+
+ // XXX assumes alphanum nicknames
+
+ if (strcmp($alias, $this->nickname) == 0) {
+ $this->clientError(
+ _('Alias can\'t be the same as nickname.'),
+ 403,
+ $this->format
+ );
+ return false;
+ }
+ }
+
+ // Evarything looks OK
+
+ return true;
+ }
+
+ /**
+ * Check to see whether a nickname is already in use by a group
+ *
+ * @param String $nickname The nickname in question
+ *
+ * @return boolean true or false
+ */
+
+ function groupNicknameExists($nickname)
+ {
+ $group = User_group::staticGet('nickname', $nickname);
+
+ if (!empty($group)) {
+ return true;
+ }
+
+ $alias = Group_alias::staticGet('alias', $nickname);
+
+ if (!empty($alias)) {
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/actions/apigroupismember.php b/actions/apigroupismember.php
new file mode 100644
index 000000000..a8a40a6b3
--- /dev/null
+++ b/actions/apigroupismember.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Check to see whether a user a member of a group
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Returns whether a user is a member of a specified group.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupIsMemberAction extends ApiBareAuthAction
+{
+ var $group = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser(null);
+ $this->group = $this->getTargetGroup(null);
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Save the new message
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ if (empty($this->group)) {
+ $this->clientError('Group not found!', 404, $this->format);
+ return false;
+ }
+
+ $is_member = $this->user->isMember($this->group);
+
+ switch($this->format) {
+ case 'xml':
+ $this->initDocument('xml');
+ $this->element('is_member', null, $is_member);
+ $this->endDocument('xml');
+ break;
+ case 'json':
+ $this->initDocument('json');
+ $this->showJsonObjects(array('is_member' => $is_member));
+ $this->endDocument('json');
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 400,
+ $this->format
+ );
+ break;
+ }
+ }
+
+}
diff --git a/actions/apigroupjoin.php b/actions/apigroupjoin.php
new file mode 100644
index 000000000..071cd9290
--- /dev/null
+++ b/actions/apigroupjoin.php
@@ -0,0 +1,163 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Join a group via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Joins the authenticated user to the group speicified by ID
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupJoinAction extends ApiAuthAction
+{
+ var $group = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->group = $this->getTargetGroup($this->arg('id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Save the new message
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ if (empty($this->group)) {
+ $this->clientError('Group not found!', 404, $this->format);
+ return false;
+ }
+
+ if ($this->user->isMember($this->group)) {
+ $this->clientError(
+ _('You are already a member of that group.'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ if (Group_block::isBlocked($this->group, $this->user->getProfile())) {
+ $this->clientError(
+ _('You have been blocked from that group by the admin.'),
+ 403,
+ $this->format
+ );
+ return;
+ }
+
+ $member = new Group_member();
+
+ $member->group_id = $this->group->id;
+ $member->profile_id = $this->user->id;
+ $member->created = common_sql_now();
+
+ $result = $member->insert();
+
+ if (!$result) {
+ common_log_db_error($member, 'INSERT', __FILE__);
+ $this->serverError(
+ sprintf(
+ _('Could not join user %s to group %s.'),
+ $this->user->nickname,
+ $this->group->nickname
+ )
+ );
+ return;
+ }
+
+ switch($this->format) {
+ case 'xml':
+ $this->show_single_xml_group($this->group);
+ break;
+ case 'json':
+ $this->showSingleJsonGroup($this->group);
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+ }
+
+}
diff --git a/actions/apigroupleave.php b/actions/apigroupleave.php
new file mode 100644
index 000000000..0d4bb9e4d
--- /dev/null
+++ b/actions/apigroupleave.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Leave a group via the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Removes the authenticated user from the group specified by ID
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupLeaveAction extends ApiAuthAction
+{
+ var $group = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->group = $this->getTargetGroup($this->arg('id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Save the new message
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400,
+ $this->format
+ );
+ return;
+ }
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ if (empty($this->group)) {
+ $this->clientError('Group not found!', 404, $this->format);
+ return false;
+ }
+
+ $member = new Group_member();
+
+ $member->group_id = $this->group->id;
+ $member->profile_id = $this->auth->id;
+
+ if (!$member->find(true)) {
+ $this->serverError(_('You are not a member of this group.'));
+ return;
+ }
+
+ $result = $member->delete();
+
+ if (!$result) {
+ common_log_db_error($member, 'INSERT', __FILE__);
+ $this->serverError(
+ sprintf(
+ _('Could not remove user %s to group %s.'),
+ $this->user->nickname,
+ $this->$group->nickname
+ )
+ );
+ return;
+ }
+
+ switch($this->format) {
+ case 'xml':
+ $this->show_single_xml_group($this->group);
+ break;
+ case 'json':
+ $this->showSingleJsonGroup($this->group);
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+ }
+
+}
diff --git a/actions/apigrouplist.php b/actions/apigrouplist.php
new file mode 100644
index 000000000..c529c1e40
--- /dev/null
+++ b/actions/apigrouplist.php
@@ -0,0 +1,223 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Check to see whether a user a member of a group
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Returns whether a user is a member of a specified group.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupListAction extends ApiBareAuthAction
+{
+ var $groups = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser($id);
+ $this->groups = $this->getGroups();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Show the user's groups
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s's groups"), $this->user->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:Groups";
+ $link = common_local_url(
+ 'usergroups',
+ array('nickname' => $this->user->nickname)
+ );
+ $subtitle = sprintf(
+ _("Groups %s is a member of on %s."),
+ $this->user->nickname,
+ $sitename
+ );
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlGroups($this->groups);
+ break;
+ case 'rss':
+ $this->showRssGroups($this->groups, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() . 'api/statusnet/groups/list/' .
+ $this->user->id . '.atom';
+ $this->showAtomGroups(
+ $this->groups,
+ $title,
+ $id,
+ $link,
+ $subtitle,
+ $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonGroups($this->groups);
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+
+ }
+
+ /**
+ * Get groups
+ *
+ * @return array groups
+ */
+
+ function getGroups()
+ {
+ $groups = array();
+
+ $group = $this->user->getGroups(
+ ($this->page - 1) * $this->count,
+ $this->count,
+ $this->since_id,
+ $this->max_id,
+ $this->since
+ );
+
+ while ($group->fetch()) {
+ $groups[] = clone($group);
+ }
+
+ return $groups;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest group the user has joined
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->groups) && (count($this->groups) > 0)) {
+ return strtotime($this->groups[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this list of groups
+ *
+ * Returns an Etag based on the action name, language, user ID and
+ * timestamps of the first and last group the user has joined
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->groups) && (count($this->groups) > 0)) {
+
+ $last = count($this->groups) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->user->id,
+ strtotime($this->groups[0]->created),
+ strtotime($this->groups[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apigrouplistall.php b/actions/apigrouplistall.php
new file mode 100644
index 000000000..89469f36f
--- /dev/null
+++ b/actions/apigrouplistall.php
@@ -0,0 +1,208 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show the newest groups
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Returns of the lastest 20 groups for the site
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupListAllAction extends ApiAction
+{
+ var $groups = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser($id);
+ $this->groups = $this->getGroups();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Show the user's groups
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s groups"), $sitename);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:Groups";
+ $link = common_local_url('groups');
+ $subtitle = sprintf(_("groups on %s"), $sitename);
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlGroups($this->groups);
+ break;
+ case 'rss':
+ $this->showRssGroups($this->groups, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() .
+ 'api/statusnet/groups/list_all.atom';
+ $this->showAtomGroups(
+ $this->groups,
+ $title,
+ $id,
+ $link,
+ $subtitle,
+ $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonGroups($this->groups);
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+
+ }
+
+ /**
+ * Get groups
+ *
+ * @return array groups
+ */
+
+ function getGroups()
+ {
+ $groups = array();
+
+ // XXX: Use the $page, $count, $max_id, $since_id, and $since parameters
+
+ $group = new User_group();
+ $group->orderBy('created DESC');
+ $group->find();
+
+ while ($group->fetch()) {
+ $groups[] = clone($group);
+ }
+
+ return $groups;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the site's latest group
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->groups) && (count($this->groups) > 0)) {
+ return strtotime($this->groups[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this list of groups
+ *
+ * Returns an Etag based on the action name, language, and
+ * timestamps of the first and last group the user has joined
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->groups) && (count($this->groups) > 0)) {
+
+ $last = count($this->groups) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ strtotime($this->groups[0]->created),
+ strtotime($this->groups[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apigroupmembership.php b/actions/apigroupmembership.php
new file mode 100644
index 000000000..b31e47b39
--- /dev/null
+++ b/actions/apigroupmembership.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List a group's members
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * List 20 newest members of the group specified by name or ID.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupMembershipAction extends ApiAction
+{
+ var $group = null;
+ var $profiles = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->group = $this->getTargetGroup($this->arg('id'));
+ $this->profiles = $this->getProfiles();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Show the members of the group
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ // XXX: RSS and Atom
+
+ switch($this->format) {
+ case 'xml':
+ $this->showTwitterXmlUsers($this->profiles);
+ break;
+ case 'json':
+ $this->showJsonUsers($this->profiles);
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+ }
+
+ /**
+ * Fetch the members of a group
+ *
+ * @return array $profiles list of profiles
+ */
+
+ function getProfiles()
+ {
+ $profiles = array();
+
+ $profile = $this->group->getMembers(
+ ($this->page - 1) * $this->count,
+ $this->count,
+ $this->since_id,
+ $this->max_id,
+ $this->since
+ );
+
+ while ($profile->fetch()) {
+ $profiles[] = clone($profile);
+ }
+
+ return $profiles;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this list of profiles last modified?
+ *
+ * @return string datestamp of the lastest profile in the group
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->profiles) && (count($this->profiles) > 0)) {
+ return strtotime($this->profiles[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this list of groups
+ *
+ * Returns an Etag based on the action name, language
+ * the group id, and timestamps of the first and last
+ * user who has joined the group
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->profiles) && (count($this->profiles) > 0)) {
+
+ $last = count($this->profiles) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->group->id,
+ strtotime($this->profiles[0]->created),
+ strtotime($this->profiles[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apigroupshow.php b/actions/apigroupshow.php
new file mode 100644
index 000000000..2bdb22bc4
--- /dev/null
+++ b/actions/apigroupshow.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show information about a group
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Outputs detailed information about the group specified by ID
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiGroupShowAction extends ApiAction
+{
+ var $group = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->group = $this->getTargetGroup($this->arg('id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (empty($this->group)) {
+ $this->clientError(
+ 'Group not found!',
+ 404,
+ $this->format
+ );
+ return;
+ }
+
+ switch($this->format) {
+ case 'xml':
+ $this->show_single_xml_group($this->group);
+ break;
+ case 'json':
+ $this->showSingleJsonGroup($this->group);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), 404, $this->format);
+ break;
+ }
+
+ }
+
+ /**
+ * When was this group last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->group)) {
+ return strtotime($this->group->modified);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this group
+ *
+ * Returns an Etag based on the action name, language, and
+ * timestamps of the notice
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->group)) {
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->group->id,
+ strtotime($this->group->modified))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apihelptest.php b/actions/apihelptest.php
new file mode 100644
index 000000000..e4ef55f2e
--- /dev/null
+++ b/actions/apihelptest.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Test that you can connect to the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Returns the string "ok" in the requested format with a 200 OK HTTP status code.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiHelpTestAction extends ApiAction
+{
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($this->format == 'xml') {
+ $this->initDocument('xml');
+ $this->element('ok', null, 'true');
+ $this->endDocument('xml');
+ } elseif ($this->format == 'json') {
+ $this->initDocument('json');
+ print '"ok"';
+ $this->endDocument('json');
+ } else {
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ }
+ }
+
+}
+
diff --git a/actions/apistatusesdestroy.php b/actions/apistatusesdestroy.php
new file mode 100644
index 000000000..8dc8793b5
--- /dev/null
+++ b/actions/apistatusesdestroy.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Destroy a notice through the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Tom Blankenship <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Deletes one of the authenticating user's statuses (notices).
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Tom Blankenship <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiStatusesDestroyAction extends ApiAuthAction
+{
+ var $status = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+ $this->notice_id = (int)$this->trimmed('id');
+
+ if (empty($notice_id)) {
+ $this->notice_id = (int)$this->arg('id');
+ }
+
+ $this->notice = Notice::staticGet((int)$this->notice_id);
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Delete the notice and all related replies
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(_('API method not found!'), $code = 404);
+ return;
+ }
+
+ if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
+ $this->clientError(_('This method requires a POST or DELETE.'),
+ 400, $this->format);
+ return;
+ }
+
+ if (empty($this->notice)) {
+ $this->clientError(_('No status found with that ID.'),
+ 404, $this->format);
+ return;
+ }
+
+ if ($this->user->id == $this->notice->profile_id) {
+ $replies = new Reply;
+ $replies->get('notice_id', $this->notice_id);
+ $replies->delete();
+ $this->notice->delete();
+
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ } else {
+ $this->clientError(_('You may not delete another user\'s status.'),
+ 403, $this->format);
+ }
+
+ $this->showNotice();
+ }
+
+ /**
+ * Show the deleted notice
+ *
+ * @return void
+ */
+
+ function showNotice()
+ {
+ if (!empty($this->notice)) {
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ }
+ }
+
+}
diff --git a/actions/apistatusesshow.php b/actions/apistatusesshow.php
new file mode 100644
index 000000000..3be22ca59
--- /dev/null
+++ b/actions/apistatusesshow.php
@@ -0,0 +1,206 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a notice (as a Twitter-style status)
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Tom Blankenship <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Returns the notice specified by id as a Twitter-style status and inline user
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Tom Blankenship <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiStatusesShowAction extends ApiAction
+{
+
+ var $notice_id = null;
+ var $notice = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ // 'id' is an undocumented parameter in Twitter's API. Several
+ // clients make use of it, so we support it too.
+
+ // show.json?id=12345 takes precedence over /show/12345.json
+
+ $this->notice_id = (int)$this->trimmed('id');
+
+ if (empty($notice_id)) {
+ $this->notice_id = (int)$this->arg('id');
+ }
+
+ $this->notice = Notice::staticGet((int)$this->notice_id);
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the notice
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(_('API method not found!'), $code = 404);
+ return;
+ }
+
+ $this->showNotice();
+ }
+
+ /**
+ * Show the notice
+ *
+ * @return void
+ */
+
+ function showNotice()
+ {
+ if (!empty($this->notice)) {
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ } else {
+
+ // XXX: Twitter just sets a 404 header and doens't bother
+ // to return an err msg
+
+ $deleted = Deleted_notice::staticGet($this->notice_id);
+
+ if (!empty($deleted)) {
+ $this->clientError(
+ _('Status deleted.'),
+ 410,
+ $this->format
+ );
+ } else {
+ $this->clientError(
+ _('No status with that ID found.'),
+ 404,
+ $this->format
+ );
+ }
+ }
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this notice last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notice)) {
+ return strtotime($this->notice->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this notice
+ *
+ * Returns an Etag based on the action name, language, and
+ * timestamps of the notice
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notice)) {
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->notice->id,
+ strtotime($this->notice->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apistatusesupdate.php b/actions/apistatusesupdate.php
new file mode 100644
index 000000000..0d71e1512
--- /dev/null
+++ b/actions/apistatusesupdate.php
@@ -0,0 +1,241 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Post a notice (update your status) through the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Tom Blankenship <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apiauth.php';
+
+/**
+ * Updates the authenticating user's status (posts a notice).
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Tom Blankenship <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiStatusesUpdateAction extends ApiAuthAction
+{
+ var $source = null;
+ var $status = null;
+ var $in_reply_to_status_id = null;
+
+ static $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->auth_user;
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return false;
+ }
+
+ $this->status = $this->trimmed('status');
+
+ if (empty($this->status)) {
+ $this->clientError(
+ 'Client must provide a \'status\' parameter with a value.',
+ 400,
+ $this->format
+ );
+
+ return false;
+ }
+
+ $this->source = $this->trimmed('source');
+
+ if (empty($this->source) || in_array($source, $this->reserved_sources)) {
+ $this->source = 'api';
+ }
+
+ $this->in_reply_to_status_id
+ = intval($this->trimmed('in_reply_to_status_id'));
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Make a new notice for the update, save it, and show it
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+ $this->clientError(
+ _('This method requires a POST.'),
+ 400, $this->format
+ );
+ return;
+ }
+
+ $status_shortened = common_shorten_links($this->status);
+
+ if (Notice::contentTooLong($status_shortened)) {
+
+ // Note: Twitter truncates anything over 140, flags the status
+ // as "truncated."
+
+ $this->clientError(
+ sprintf(
+ _('That\'s too long. Max notice size is %d chars.'),
+ Notice::maxContent()
+ ),
+ 406,
+ $this->format
+ );
+
+ return;
+ }
+
+ // Check for commands
+
+ $inter = new CommandInterpreter();
+ $cmd = $inter->handle_command($this->user, $status_shortened);
+
+ if ($cmd) {
+
+ if ($this->supported($cmd)) {
+ $cmd->execute(new Channel());
+ }
+
+ // Cmd not supported? Twitter just returns your latest status.
+ // And, it returns your last status whether the cmd was successful
+ // or not!
+
+ $this->notice = $this->user->getCurrentNotice();
+
+ } else {
+
+ $reply_to = null;
+
+ if (!empty($this->in_reply_to_status_id)) {
+
+ // Check whether notice actually exists
+
+ $reply = Notice::staticGet($this->in_reply_to_status_id);
+
+ if ($reply) {
+ $reply_to = $this->in_reply_to_status_id;
+ } else {
+ $this->clientError(
+ _('Not found'),
+ $code = 404,
+ $this->format
+ );
+ return;
+ }
+ }
+
+ $this->notice = Notice::saveNew(
+ $this->user->id,
+ html_entity_decode($this->status, ENT_NOQUOTES, 'UTF-8'),
+ $this->source,
+ 1,
+ $reply_to
+ );
+
+ common_broadcast_notice($this->notice);
+ }
+
+ $this->showNotice();
+ }
+
+ /**
+ * Show the resulting notice
+ *
+ * @return void
+ */
+
+ function showNotice()
+ {
+ if (!empty($this->notice)) {
+ if ($this->format == 'xml') {
+ $this->showSingleXmlStatus($this->notice);
+ } elseif ($this->format == 'json') {
+ $this->show_single_json_status($this->notice);
+ }
+ }
+ }
+
+ /**
+ * Is this command supported when doing an update from the API?
+ *
+ * @param string $cmd the command to check for
+ *
+ * @return boolean true or false
+ */
+
+ function supported($cmd)
+ {
+ static $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand',
+ 'FavCommand', 'OnCommand', 'OffCommand');
+
+ if (in_array(get_class($cmd), $cmdlist)) {
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/actions/apistatusnetconfig.php b/actions/apistatusnetconfig.php
new file mode 100644
index 000000000..ed1d151bf
--- /dev/null
+++ b/actions/apistatusnetconfig.php
@@ -0,0 +1,142 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Dump of configuration variables
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Gives a full dump of configuration variables for this instance
+ * of StatusNet, minus variables that may be security-sensitive (like
+ * passwords).
+ * URL: http://identi.ca/api/statusnet/config.(xml|json)
+ * Formats: xml, json
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiStatusnetConfigAction extends ApiAction
+{
+ var $keys = array(
+ 'site' => array('name', 'server', 'theme', 'path', 'fancy', 'language',
+ 'email', 'broughtby', 'broughtbyurl', 'closed',
+ 'inviteonly', 'private'),
+ 'license' => array('url', 'title', 'image'),
+ 'nickname' => array('featured'),
+ 'throttle' => array('enabled', 'count', 'timespan'),
+ 'xmpp' => array('enabled', 'server', 'user')
+ );
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ switch ($this->format) {
+ case 'xml':
+ $this->initDocument('xml');
+ $this->elementStart('config');
+
+ // XXX: check that all sections and settings are legal XML elements
+
+ common_debug(var_export($this->keys, true));
+
+ foreach ($this->keys as $section => $settings) {
+ $this->elementStart($section);
+ foreach ($settings as $setting) {
+ $value = common_config($section, $setting);
+ if (is_array($value)) {
+ $value = implode(',', $value);
+ } else if ($value === false) {
+ $value = 'false';
+ } else if ($value === true) {
+ $value = 'true';
+ }
+ $this->element($setting, null, $value);
+ }
+ $this->elementEnd($section);
+ }
+ $this->elementEnd('config');
+ $this->endDocument('xml');
+ break;
+ case 'json':
+ $result = array();
+ foreach ($this->keys as $section => $settings) {
+ $result[$section] = array();
+ foreach ($settings as $setting) {
+ $result[$section][$setting]
+ = common_config($section, $setting);
+ }
+ }
+ $this->initDocument('json');
+ $this->showJsonObjects($result);
+ $this->endDocument('json');
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+ }
+
+}
+
diff --git a/actions/apistatusnetversion.php b/actions/apistatusnetversion.php
new file mode 100644
index 000000000..e73ab983b
--- /dev/null
+++ b/actions/apistatusnetversion.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * A version stamp for the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Returns a version number for this version of StatusNet, which
+ * should make things a bit easier for upgrades.
+ * URL: http://identi.ca/api/statusnet/version.(xml|json)
+ * Formats: xml, js
+ *
+ * @category API
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiStatusnetVersionAction extends ApiAction
+{
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ switch ($this->format) {
+ case 'xml':
+ $this->initDocument('xml');
+ $this->element('version', null, STATUSNET_VERSION);
+ $this->endDocument('xml');
+ break;
+ case 'json':
+ $this->initDocument('json');
+ print '"'.STATUSNET_VERSION.'"';
+ $this->endDocument('json');
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+ }
+
+}
+
diff --git a/actions/apisubscriptions.php b/actions/apisubscriptions.php
new file mode 100644
index 000000000..bc68dd192
--- /dev/null
+++ b/actions/apisubscriptions.php
@@ -0,0 +1,266 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Base class for showing subscription information in the API
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * This class outputs a list of profiles as Twitter-style user and status objects.
+ * It is used by the API methods /api/statuses/(friends|followers). To support the
+ * social graph methods it also can output a simple list of IDs.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiSubscriptionsAction extends ApiBareAuthAction
+{
+ var $profiles = null;
+ var $tag = null;
+ var $lite = null;
+ var $ids_only = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->tag = $this->arg('tag');
+
+ // Note: Twitter no longer supports 'lite'
+ $this->lite = $this->arg('lite');
+
+ $this->ids_only = $this->arg('ids_only');
+
+ // If called as a social graph method, show 5000 per page, otherwise 100
+
+ $this->count = isset($this->ids_only) ?
+ 5000 : (int)$this->arg('count', 100);
+
+ $this->user = $this->getTargetUser($this->arg('id'));
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return false;
+ }
+
+ $this->profiles = $this->getProfiles();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Show the profiles
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(_('API method not found!'), $code = 404);
+ return;
+ }
+
+ $this->initDocument($this->format);
+
+ if (isset($this->ids_only)) {
+ $this->showIds();
+ } else {
+ $this->showProfiles(isset($this->lite) ? false : true);
+ }
+
+ $this->endDocument($this->format);
+ }
+
+ /**
+ * Get profiles - should get overrrided
+ *
+ * @return array Profiles
+ */
+
+ function getProfiles()
+ {
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest profile in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->profiles) && (count($this->profiles) > 0)) {
+ return strtotime($this->profiles[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this action
+ *
+ * Returns an Etag based on the action name, language, user ID, and
+ * timestamps of the first and last profiles in the subscriptions list
+ * There's also an indicator to show whether this action is being called
+ * as /api/statuses/(friends|followers) or /api/(friends|followers)/ids
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->profiles) && (count($this->profiles) > 0)) {
+
+ $last = count($this->profiles) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->user->id,
+ isset($this->ids_only) ? 'IDs' : 'Profiles',
+ strtotime($this->profiles[0]->created),
+ strtotime($this->profiles[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+ /**
+ * Show the profiles as Twitter-style useres and statuses
+ *
+ * @param boolean $include_statuses Whether to include the latest status
+ * with each user. Default true.
+ *
+ * @return void
+ */
+
+ function showProfiles($include_statuses = true)
+ {
+ switch ($this->format) {
+ case 'xml':
+ $this->elementStart('users', array('type' => 'array'));
+ foreach ($this->profiles as $profile) {
+ $this->showProfile(
+ $profile,
+ $this->format,
+ null,
+ $include_statuses
+ );
+ }
+ $this->elementEnd('users');
+ break;
+ case 'json':
+ $arrays = array();
+ foreach ($this->profiles as $profile) {
+ $arrays[] = $this->twitterUserArray(
+ $profile,
+ $include_statuses
+ );
+ }
+ print json_encode($arrays);
+ break;
+ default:
+ $this->clientError(_('Unsupported format.'));
+ break;
+ }
+ }
+
+ /**
+ * Show the IDs of the profiles only. 5000 per page. To support
+ * the 'social graph' methods: /api/(friends|followers)/ids
+ *
+ * @return void
+ */
+
+ function showIds()
+ {
+ switch ($this->format) {
+ case 'xml':
+ $this->elementStart('ids');
+ foreach ($this->profiles as $profile) {
+ $this->element('id', null, $profile->id);
+ }
+ $this->elementEnd('ids');
+ break;
+ case 'json':
+ $ids = array();
+ foreach ($this->profiles as $profile) {
+ $ids[] = (int)$profile->id;
+ }
+ print json_encode($ids);
+ break;
+ default:
+ $this->clientError(_('Unsupported format.'));
+ break;
+ }
+ }
+
+}
diff --git a/actions/apitimelinefavorites.php b/actions/apitimelinefavorites.php
new file mode 100644
index 000000000..b8ae74f13
--- /dev/null
+++ b/actions/apitimelinefavorites.php
@@ -0,0 +1,237 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's favorite notices
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net> * @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);
+}
+
+require_once INSTALLDIR.'/lib/apibareauth.php';
+
+/**
+ * Returns the 20 most recent favorite notices for the authenticating user or user
+ * specified by the ID parameter in the requested format.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiTimelineFavoritesAction extends ApiBareAuthAction
+{
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser($this->arg('id'));
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+
+ function showTimeline()
+ {
+ $profile = $this->user->getProfile();
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(
+ _('%s / Favorites from %s'),
+ $sitename,
+ $this->user->nickname
+ );
+
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:Favorites:" . $this->user->id;
+ $link = common_local_url(
+ 'favorites',
+ array('nickname' => $this->user->nickname)
+ );
+ $subtitle = sprintf(
+ _('%s updates favorited by %s / %s.'),
+ $sitename,
+ $profile->getBestName(),
+ $this->user->nickname
+ );
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline($this->notices, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() .
+ ltrim($_SERVER['QUERY_STRING'], 'p=');
+ $this->showAtomTimeline(
+ $this->notices, $title, $id, $link, $subtitle,
+ null, $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getNotices()
+ {
+ $notices = array();
+
+ if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
+ $notice = $this->user->favoriteNotices(
+ ($this->page-1) * $this->count,
+ $this->count,
+ true
+ );
+ } else {
+ $notice = $this->user->favoriteNotices(
+ ($this->page-1) * $this->count,
+ $this->count,
+ false
+ );
+ }
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, user ID, and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->user->id,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apitimelinefriends.php b/actions/apitimelinefriends.php
new file mode 100644
index 000000000..1ea35866e
--- /dev/null
+++ b/actions/apitimelinefriends.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show the friends timeline
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Returns the most recent notices (default 20) posted by the target user.
+ * This is the equivalent of 'You and friends' page accessed via Web.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiTimelineFriendsAction extends ApiBareAuthAction
+{
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser($this->arg('id'));
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+
+ function showTimeline()
+ {
+ $profile = $this->user->getProfile();
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s and friends"), $this->user->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:FriendsTimeline:" . $this->user->id;
+ $link = common_local_url(
+ 'all', array('nickname' => $this->user->nickname)
+ );
+ $subtitle = sprintf(
+ _('Updates from %1$s and friends on %2$s!'),
+ $this->user->nickname, $sitename
+ );
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline($this->notices, $title, $link, $subtitle);
+ break;
+ case 'atom':
+
+ $target_id = $this->arg('id');
+
+ if (isset($target_id)) {
+ $selfuri = common_root_url() .
+ 'api/statuses/friends_timeline/' .
+ $target_id . '.atom';
+ } else {
+ $selfuri = common_root_url() .
+ 'api/statuses/friends_timeline.atom';
+ }
+
+ $this->showAtomTimeline(
+ $this->notices, $title, $id, $link,
+ $subtitle, null, $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getNotices()
+ {
+ $notices = array();
+
+ if (!empty($this->auth_user) && $this->auth_user->id == $this->user->id) {
+ $notice = $this->user->noticeInbox(
+ ($this->page-1) * $this->count,
+ $this->count, $this->since_id,
+ $this->max_id, $this->since
+ );
+ } else {
+ $notice = $this->user->noticesWithFriends(
+ ($this->page-1) * $this->count,
+ $this->count, $this->since_id,
+ $this->max_id, $this->since
+ );
+ }
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, user ID, and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->user->id,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apitimelinegroup.php b/actions/apitimelinegroup.php
new file mode 100644
index 000000000..5d0542918
--- /dev/null
+++ b/actions/apitimelinegroup.php
@@ -0,0 +1,231 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a group's notices
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Returns the most recent notices (default 20) posted to the group specified by ID
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiTimelineGroupAction extends ApiAction
+{
+
+ var $group = null;
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->group = $this->getTargetGroup($this->arg('id'));
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+
+ function showTimeline()
+ {
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s timeline"), $this->group->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:GroupTimeline:" . $this->group->id;
+ $link = common_local_url(
+ 'showgroup',
+ array('nickname' => $this->group->nickname)
+ );
+ $subtitle = sprintf(
+ _('Updates from %1$s on %2$s!'),
+ $this->group->nickname,
+ $sitename
+ );
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline($this->notices, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() .
+ 'api/statusnet/groups/timeline/' .
+ $this->group->nickname . '.atom';
+ $this->showAtomTimeline(
+ $this->notices,
+ $title,
+ $id,
+ $link,
+ $subtitle,
+ null,
+ $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ default:
+ $this->clientError(
+ _('API method not found!'),
+ 404,
+ $this->format
+ );
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getNotices()
+ {
+ $notices = array();
+
+ $notice = $this->group->getNotices(
+ ($this->page-1) * $this->count,
+ $this->count,
+ $this->since_id,
+ $this->max_id,
+ $this->since
+ );
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, group ID and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->group->id,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apitimelinementions.php b/actions/apitimelinementions.php
new file mode 100644
index 000000000..fe5ff0f28
--- /dev/null
+++ b/actions/apitimelinementions.php
@@ -0,0 +1,233 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show notices mentioning a user (@nickname)
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Returns the most recent (default 20) mentions (status containing @nickname)
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiTimelineMentionsAction extends ApiBareAuthAction
+{
+
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser($this->arg('id'));
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+
+ function showTimeline()
+ {
+ $profile = $this->user->getProfile();
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(
+ _('%1$s / Updates mentioning %2$s'),
+ $sitename, $this->user->nickname
+ );
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:Mentions:" . $this->user->id;
+ $link = common_local_url(
+ 'replies',
+ array('nickname' => $this->user->nickname)
+ );
+ $subtitle = sprintf(
+ _('%1$s updates that reply to updates from %2$s / %3$s.'),
+ $sitename, $this->user->nickname, $profile->getBestName()
+ );
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline($this->notices, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() .
+ ltrim($_SERVER['QUERY_STRING'], 'p=');
+ $this->showAtomTimeline(
+ $this->notices, $title, $id, $link, $subtitle,
+ null, $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getNotices()
+ {
+ $notices = array();
+
+ $notice = $this->user->getReplies(
+ ($this->page - 1) * $this->count, $this->count,
+ $this->since_id, $this->max_id, $this->since
+ );
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, user ID, and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->user->id,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apitimelinepublic.php b/actions/apitimelinepublic.php
new file mode 100644
index 000000000..58e267734
--- /dev/null
+++ b/actions/apitimelinepublic.php
@@ -0,0 +1,213 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show the public timeline
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Returns the most recent notices (default 20) posted by everybody
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiTimelinePublicAction extends ApiAction
+{
+
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+
+ function showTimeline()
+ {
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s public timeline"), $sitename);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:PublicTimeline";
+ $link = common_root_url();
+ $subtitle = sprintf(_("%s updates from everyone!"), $sitename);
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline($this->notices, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() . 'api/statuses/public_timeline.atom';
+ $this->showAtomTimeline(
+ $this->notices, $title, $id, $link,
+ $subtitle, null, $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getNotices()
+ {
+ $notices = array();
+
+ $notice = Notice::publicStream(
+ ($this->page - 1) * $this->count, $this->count, $this->since_id,
+ $this->max_id, $this->since
+ );
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apitimelinetag.php b/actions/apitimelinetag.php
new file mode 100644
index 000000000..a274daac0
--- /dev/null
+++ b/actions/apitimelinetag.php
@@ -0,0 +1,224 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show the latest notices for a given tag
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Returns the 20 most recent notices tagged by a given tag
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiTimelineTagAction extends ApiAction
+{
+
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->tag = $this->arg('tag');
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+
+ function showTimeline()
+ {
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("Notices tagged with %s"), $this->tag);
+ $link = common_local_url(
+ 'tag',
+ array('tag' => $this->tag)
+ );
+ $subtitle = sprintf(
+ _('Updates tagged with %1$s on %2$s!'),
+ $this->tag,
+ $sitename
+ );
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:TagTimeline:".$tag;
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline($this->notices, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() .
+ 'api/statusnet/tags/timeline/' .
+ $this->tag . '.atom';
+ $this->showAtomTimeline(
+ $this->notices,
+ $title,
+ $id,
+ $link,
+ $subtitle,
+ null,
+ $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getNotices()
+ {
+ $notices = array();
+
+ $notice = Notice_tag::getStream(
+ $this->tag,
+ ($this->page - 1) * $this->count,
+ $this->count + 1
+ );
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->tag,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apitimelineuser.php b/actions/apitimelineuser.php
new file mode 100644
index 000000000..285735fd1
--- /dev/null
+++ b/actions/apitimelineuser.php
@@ -0,0 +1,248 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's timeline
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Returns the most recent notices (default 20) posted by the authenticating
+ * user. Another user's timeline can be requested via the id parameter. This
+ * is the API equivalent of the user profile web page.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Jeffery To <jeffery.to@gmail.com>
+ * @author mac65 <mac65@mac65.com>
+ * @author Mike Cochrane <mikec@mikenz.geek.nz>
+ * @author Robin Millette <robin@millette.info>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiTimelineUserAction extends ApiBareAuthAction
+{
+
+ var $notices = null;
+
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = $this->getTargetUser($this->arg('id'));
+
+ if (empty($this->user)) {
+ $this->clientError(_('No such user!'), 404, $this->format);
+ return;
+ }
+
+ $this->notices = $this->getNotices();
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Just show the notices
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showTimeline();
+ }
+
+ /**
+ * Show the timeline of notices
+ *
+ * @return void
+ */
+
+ function showTimeline()
+ {
+ $profile = $this->user->getProfile();
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s timeline"), $this->user->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:UserTimeline:" . $this->user->id;
+ $link = common_local_url(
+ 'showstream',
+ array('nickname' => $this->user->nickname)
+ );
+ $subtitle = sprintf(
+ _('Updates from %1$s on %2$s!'),
+ $this->user->nickname, $sitename
+ );
+
+ // FriendFeed's SUP protocol
+ // Also added RSS and Atom feeds
+
+ $suplink = common_local_url('sup', null, null, $this->user->id);
+ header('X-SUP-ID: ' . $suplink);
+
+ switch($this->format) {
+ case 'xml':
+ $this->showXmlTimeline($this->notices);
+ break;
+ case 'rss':
+ $this->showRssTimeline(
+ $this->notices, $title, $link,
+ $subtitle, $suplink
+ );
+ break;
+ case 'atom':
+ if (isset($apidata['api_arg'])) {
+ $selfuri = common_root_url() .
+ 'api/statuses/user_timeline/' .
+ $apidata['api_arg'] . '.atom';
+ } else {
+ $selfuri = common_root_url() .
+ 'api/statuses/user_timeline.atom';
+ }
+ $this->showAtomTimeline(
+ $this->notices, $title, $id, $link,
+ $subtitle, $suplink, $selfuri
+ );
+ break;
+ case 'json':
+ $this->showJsonTimeline($this->notices);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+
+ }
+
+ /**
+ * Get notices
+ *
+ * @return array notices
+ */
+
+ function getNotices()
+ {
+ $notices = array();
+
+ $notice = $this->user->getNotices(
+ ($this->page-1) * $this->count, $this->count,
+ $this->since_id, $this->max_id, $this->since
+ );
+
+ while ($notice->fetch()) {
+ $notices[] = clone($notice);
+ }
+
+ return $notices;
+ }
+
+ /**
+ * Is this action read only?
+ *
+ * @param array $args other arguments
+ *
+ * @return boolean true
+ */
+
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * When was this feed last modified?
+ *
+ * @return string datestamp of the latest notice in the stream
+ */
+
+ function lastModified()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+ return strtotime($this->notices[0]->created);
+ }
+
+ return null;
+ }
+
+ /**
+ * An entity tag for this stream
+ *
+ * Returns an Etag based on the action name, language, user ID, and
+ * timestamps of the first and last notice in the timeline
+ *
+ * @return string etag
+ */
+
+ function etag()
+ {
+ if (!empty($this->notices) && (count($this->notices) > 0)) {
+
+ $last = count($this->notices) - 1;
+
+ return '"' . implode(
+ ':',
+ array($this->arg('action'),
+ common_language(),
+ $this->user->id,
+ strtotime($this->notices[0]->created),
+ strtotime($this->notices[$last]->created))
+ )
+ . '"';
+ }
+
+ return null;
+ }
+
+}
diff --git a/actions/apiuserfollowers.php b/actions/apiuserfollowers.php
new file mode 100644
index 000000000..e8d92a773
--- /dev/null
+++ b/actions/apiuserfollowers.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's followers (subscribers)
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Ouputs the authenticating user's followers (subscribers), each with
+ * current Twitter-style status inline. They are ordered by the order
+ * in which they subscribed to the user, 100 at a time.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiUserFollowersAction extends ApiSubscriptionsAction
+{
+ /**
+ * Get the user's subscribers (followers) as an array of profiles
+ *
+ * @return array Profiles
+ */
+
+ function getProfiles()
+ {
+ $offset = ($this->page - 1) * $this->count;
+ $limit = $this->count + 1;
+
+ $subs = null;
+
+ if (isset($this->tag)) {
+ $subs = $this->user->getTaggedSubscribers(
+ $this->tag, $offset, $limit
+ );
+ } else {
+ $subs = $this->user->getSubscribers(
+ $offset,
+ $limit
+ );
+ }
+
+ $profiles = array();
+
+ if (!empty($subs)) {
+ while ($subs->fetch()) {
+ $profiles[] = clone($subs);
+ }
+ }
+
+ return $profiles;
+ }
+
+}
diff --git a/actions/apiuserfriends.php b/actions/apiuserfriends.php
new file mode 100644
index 000000000..741a26e58
--- /dev/null
+++ b/actions/apiuserfriends.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's friends (subscriptions)
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/apibareauth.php';
+
+/**
+ * Ouputs the authenticating user's friends (subscriptions), each with
+ * current Twitter-style status inline. They are ordered by the date
+ * in which the user subscribed to them, 100 at a time.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiUserFriendsAction extends ApiSubscriptionsAction
+{
+ /**
+ * Get the user's subscriptions (friends) as an array of profiles
+ *
+ * @return array Profiles
+ */
+
+ function getProfiles()
+ {
+ $offset = ($this->page - 1) * $this->count;
+ $limit = $this->count + 1;
+
+ $subs = null;
+
+ if (isset($this->tag)) {
+ $subs = $this->user->getTaggedSubscriptions(
+ $this->tag, $offset, $limit
+ );
+ } else {
+ $subs = $this->user->getSubscriptions(
+ $offset,
+ $limit
+ );
+ }
+
+ $profiles = array();
+
+ if (!empty($subs)) {
+ while ($subs->fetch()) {
+ $profiles[] = clone($subs);
+ }
+ }
+
+ return $profiles;
+ }
+
+}
diff --git a/actions/apiusershow.php b/actions/apiusershow.php
new file mode 100644
index 000000000..b3a939b43
--- /dev/null
+++ b/actions/apiusershow.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Show a user's profile information
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author mac65 <mac65@mac65.com>
+ * @author Zach Copley <zach@status.net>
+ * @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);
+}
+
+require_once INSTALLDIR . '/lib/api.php';
+
+/**
+ * Ouputs information for a user, specified by ID or screen name.
+ * The user's most recent status will be returned inline.
+ *
+ * @category API
+ * @package StatusNet
+ * @author Dan Moore <dan@moore.cx>
+ * @author Evan Prodromou <evan@status.net>
+ * @author mac65 <mac65@mac65.com>
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ApiUserShowAction extends ApiAction
+{
+ /**
+ * Take arguments for running
+ *
+ * @param array $args $_REQUEST args
+ *
+ * @return boolean success flag
+ *
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $email = $this->arg('email');
+
+ // XXX: email field deprecated in Twitter's API
+
+ if (!empty($email)) {
+ $this->user = User::staticGet('email', $email);
+ } else {
+ $this->user = $this->getTargetUser($this->arg('id'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle the request
+ *
+ * Check the format and show the user info
+ *
+ * @param array $args $_REQUEST data (unused)
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (empty($this->user)) {
+ $this->clientError(_('Not found.'), 404, $this->format);
+ return;
+ }
+
+ if (!in_array($this->format, array('xml', 'json'))) {
+ $this->clientError(_('API method not found!'), $code = 404);
+ return;
+ }
+
+ $profile = $this->user->getProfile();
+
+ if (empty($profile)) {
+ $this->clientError(_('User has no profile.'));
+ return;
+ }
+
+ $twitter_user = $this->twitterUserArray($this->user->getProfile(), true);
+
+ if ($this->format == 'xml') {
+ $this->initDocument('xml');
+ $this->showTwitterXmlUser($twitter_user);
+ $this->endDocument('xml');
+ } elseif ($this->format == 'json') {
+ $this->initDocument('json');
+ $this->showJsonObjects($twitter_user);
+ $this->endDocument('json');
+ }
+
+ }
+
+}
diff --git a/actions/confirmaddress.php b/actions/confirmaddress.php
index 201694286..6fd74f3ff 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/deletenotice.php b/actions/deletenotice.php
index 3d040f2fa..4a48a9c34 100644
--- a/actions/deletenotice.php
+++ b/actions/deletenotice.php
@@ -32,15 +32,45 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once INSTALLDIR.'/lib/deleteaction.php';
-
-class DeletenoticeAction extends DeleteAction
+class DeletenoticeAction extends Action
{
- var $error = null;
+ var $error = null;
+ var $user = null;
+ var $notice = null;
+ var $profile = null;
+ var $user_profile = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->user = common_current_user();
+ $notice_id = $this->trimmed('notice');
+ $this->notice = Notice::staticGet($notice_id);
+
+ if (!$this->notice) {
+ common_user_error(_('No such notice.'));
+ exit;
+ }
+
+ $this->profile = $this->notice->getProfile();
+ $this->user_profile = $this->user->getProfile();
+
+ return true;
+ }
function handle($args)
{
parent::handle($args);
+
+ if (!common_logged_in()) {
+ common_user_error(_('Not logged in.'));
+ exit;
+ } else if ($this->notice->profile_id != $this->user_profile->id &&
+ !$this->user->hasRight(Right::deleteOthersNotice)) {
+ common_user_error(_('Can\'t delete this notice.'));
+ exit;
+ }
// XXX: Ajax!
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
diff --git a/actions/doc.php b/actions/doc.php
index 68295234c..836f039d3 100644
--- a/actions/doc.php
+++ b/actions/doc.php
@@ -58,12 +58,24 @@ class DocAction extends Action
function handle($args)
{
parent::handle($args);
- $this->title = $this->trimmed('title');
- $this->filename = INSTALLDIR.'/doc-src/'.$this->title;
- if (!file_exists($this->filename)) {
- $this->clientError(_('No such document.'));
- return;
+
+ $this->title = $this->trimmed('title');
+ $this->output = null;
+
+ if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
+
+ $this->filename = INSTALLDIR.'/doc-src/'.$this->title;
+ if (!file_exists($this->filename)) {
+ $this->clientError(_('No such document.'));
+ return;
+ }
+
+ $c = file_get_contents($this->filename);
+ $this->output = common_markup_to_html($c);
+
+ Event::handle('EndLoadDoc', array($this->title, &$this->output));
}
+
$this->showPage();
}
@@ -93,9 +105,7 @@ class DocAction extends Action
*/
function showContent()
{
- $c = file_get_contents($this->filename);
- $output = common_markup_to_html($c);
- $this->raw($output);
+ $this->raw($this->output);
}
/**
diff --git a/actions/editgroup.php b/actions/editgroup.php
index b8dac31cb..cf1608035 100644
--- a/actions/editgroup.php
+++ b/actions/editgroup.php
@@ -64,11 +64,6 @@ class EditgroupAction extends GroupDesignAction
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to create a group.'));
return false;
@@ -202,8 +197,8 @@ class EditgroupAction extends GroupDesignAction
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
- } else if (!is_null($description) && mb_strlen($description) > 140) {
- $this->showForm(_('description is too long (max 140 chars).'));
+ } else if (User_group::descriptionTooLong($description)) {
+ $this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));
diff --git a/actions/favorited.php b/actions/favorited.php
index 5ba508cdf..150b67b0b 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/favoritesrss.php b/actions/favoritesrss.php
index 2d5ce9854..62f06e841 100644
--- a/actions/favoritesrss.php
+++ b/actions/favoritesrss.php
@@ -50,11 +50,11 @@ require_once INSTALLDIR.'/lib/rssaction.php';
*/
class FavoritesrssAction extends Rss10Action
{
-
+
/** The user whose favorites to display */
-
+
var $user = null;
-
+
/**
* Find the user to display by supplied nickname
*
@@ -66,7 +66,7 @@ class FavoritesrssAction extends Rss10Action
function prepare($args)
{
parent::prepare($args);
-
+
$nickname = $this->trimmed('nickname');
$this->user = User::staticGet('nickname', $nickname);
@@ -74,10 +74,11 @@ class FavoritesrssAction extends Rss10Action
$this->clientError(_('No such user.'));
return false;
} else {
+ $this->notices = $this->getNotices($this->limit);
return true;
}
}
-
+
/**
* Get notices
*
diff --git a/actions/finishaddopenid.php b/actions/finishaddopenid.php
deleted file mode 100644
index b6de4f244..000000000
--- a/actions/finishaddopenid.php
+++ /dev/null
@@ -1,185 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Complete adding an OpenID
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @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.'/lib/openid.php';
-
-/**
- * Complete adding an OpenID
- *
- * Handle the return from an OpenID verification
- *
- * @category Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-class FinishaddopenidAction extends Action
-{
- var $msg = null;
-
- /**
- * Handle the redirect back from OpenID confirmation
- *
- * Check to see if the user's logged in, and then try
- * to use the OpenID login system.
- *
- * @param array $args $_REQUEST arguments
- *
- * @return void
- */
-
- function handle($args)
- {
- parent::handle($args);
- if (!common_logged_in()) {
- $this->clientError(_('Not logged in.'));
- } else {
- $this->tryLogin();
- }
- }
-
- /**
- * Try to log in using OpenID
- *
- * Check the OpenID for validity; potentially store it.
- *
- * @return void
- */
-
- function tryLogin()
- {
- $consumer =& oid_consumer();
-
- $response = $consumer->complete(common_local_url('finishaddopenid'));
-
- if ($response->status == Auth_OpenID_CANCEL) {
- $this->message(_('OpenID authentication cancelled.'));
- return;
- } else if ($response->status == Auth_OpenID_FAILURE) {
- // Authentication failed; display the error message.
- $this->message(sprintf(_('OpenID authentication failed: %s'),
- $response->message));
- } else if ($response->status == Auth_OpenID_SUCCESS) {
-
- $display = $response->getDisplayIdentifier();
- $canonical = ($response->endpoint && $response->endpoint->canonicalID) ?
- $response->endpoint->canonicalID : $display;
-
- $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
-
- if ($sreg_resp) {
- $sreg = $sreg_resp->contents();
- }
-
- $cur =& common_current_user();
-
- $other = oid_get_user($canonical);
-
- if ($other) {
- if ($other->id == $cur->id) {
- $this->message(_('You already have this OpenID!'));
- } else {
- $this->message(_('Someone else already has this OpenID.'));
- }
- return;
- }
-
- // start a transaction
-
- $cur->query('BEGIN');
-
- $result = oid_link_user($cur->id, $canonical, $display);
-
- if (!$result) {
- $this->message(_('Error connecting user.'));
- return;
- }
- if ($sreg) {
- if (!oid_update_user($cur, $sreg)) {
- $this->message(_('Error updating profile'));
- return;
- }
- }
-
- // success!
-
- $cur->query('COMMIT');
-
- oid_set_last($display);
-
- common_redirect(common_local_url('openidsettings'), 303);
- }
- }
-
- /**
- * Show a failure message
- *
- * Something went wrong. Save the message, and show the page.
- *
- * @param string $msg Error message to show
- *
- * @return void
- */
-
- function message($msg)
- {
- $this->message = $msg;
- $this->showPage();
- }
-
- /**
- * Title of the page
- *
- * @return string title
- */
-
- function title()
- {
- return _('OpenID Login');
- }
-
- /**
- * Show error message
- *
- * @return void
- */
-
- function showPageNotice()
- {
- if ($this->message) {
- $this->element('p', 'error', $this->message);
- }
- }
-}
diff --git a/actions/finishopenidlogin.php b/actions/finishopenidlogin.php
deleted file mode 100644
index 9ac036985..000000000
--- a/actions/finishopenidlogin.php
+++ /dev/null
@@ -1,497 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-require_once(INSTALLDIR.'/lib/openid.php');
-
-class FinishopenidloginAction extends Action
-{
- var $error = null;
- var $username = null;
- var $message = null;
-
- function handle($args)
- {
- parent::handle($args);
- if (!common_config('openid', 'enabled')) {
- common_redirect(common_local_url('login'));
- } else if (common_is_real_login()) {
- $this->clientError(_('Already logged in.'));
- } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $token = $this->trimmed('token');
- if (!$token || $token != common_session_token()) {
- $this->showForm(_('There was a problem with your session token. Try again, please.'));
- return;
- }
- if ($this->arg('create')) {
- if (!$this->boolean('license')) {
- $this->showForm(_('You can\'t register if you don\'t agree to the license.'),
- $this->trimmed('newname'));
- return;
- }
- $this->createNewUser();
- } else if ($this->arg('connect')) {
- $this->connectUser();
- } else {
- common_debug(print_r($this->args, true), __FILE__);
- $this->showForm(_('Something weird happened.'),
- $this->trimmed('newname'));
- }
- } else {
- $this->tryLogin();
- }
- }
-
- function showPageNotice()
- {
- if ($this->error) {
- $this->element('div', array('class' => 'error'), $this->error);
- } else {
- $this->element('div', 'instructions',
- sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
- }
- }
-
- function title()
- {
- return _('OpenID Account Setup');
- }
-
- function showForm($error=null, $username=null)
- {
- $this->error = $error;
- $this->username = $username;
-
- $this->showPage();
- }
-
- function showContent()
- {
- if (!empty($this->message_text)) {
- $this->element('div', array('class' => 'error'), $this->message_text);
- return;
- }
-
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'account_connect',
- 'action' => common_local_url('finishopenidlogin')));
- $this->hidden('token', common_session_token());
- $this->element('h2', null,
- _('Create new account'));
- $this->element('p', null,
- _('Create a new user with this nickname.'));
- $this->input('newname', _('New nickname'),
- ($this->username) ? $this->username : '',
- _('1-64 lowercase letters or numbers, no punctuation or spaces'));
- $this->elementStart('p');
- $this->element('input', array('type' => 'checkbox',
- 'id' => 'license',
- 'name' => 'license',
- 'value' => 'true'));
- $this->text(_('My text and files are available under '));
- $this->element('a', array('href' => common_config('license', 'url')),
- common_config('license', 'title'));
- $this->text(_(' except this private data: password, email address, IM address, phone number.'));
- $this->elementEnd('p');
- $this->submit('create', _('Create'));
- $this->element('h2', null,
- _('Connect existing account'));
- $this->element('p', null,
- _('If you already have an account, login with your username and password to connect it to your OpenID.'));
- $this->input('nickname', _('Existing nickname'));
- $this->password('password', _('Password'));
- $this->submit('connect', _('Connect'));
- $this->elementEnd('form');
- }
-
- function tryLogin()
- {
- $consumer = oid_consumer();
-
- $response = $consumer->complete(common_local_url('finishopenidlogin'));
-
- if ($response->status == Auth_OpenID_CANCEL) {
- $this->message(_('OpenID authentication cancelled.'));
- return;
- } else if ($response->status == Auth_OpenID_FAILURE) {
- // Authentication failed; display the error message.
- $this->message(sprintf(_('OpenID authentication failed: %s'), $response->message));
- } else if ($response->status == Auth_OpenID_SUCCESS) {
- // This means the authentication succeeded; extract the
- // identity URL and Simple Registration data (if it was
- // returned).
- $display = $response->getDisplayIdentifier();
- $canonical = ($response->endpoint->canonicalID) ?
- $response->endpoint->canonicalID : $response->getDisplayIdentifier();
-
- $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
-
- if ($sreg_resp) {
- $sreg = $sreg_resp->contents();
- }
-
- $user = oid_get_user($canonical);
-
- if ($user) {
- oid_set_last($display);
- # XXX: commented out at @edd's request until better
- # control over how data flows from OpenID provider.
- # oid_update_user($user, $sreg);
- common_set_user($user);
- common_real_login(true);
- if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
- common_rememberme($user);
- }
- unset($_SESSION['openid_rememberme']);
- $this->goHome($user->nickname);
- } else {
- $this->saveValues($display, $canonical, $sreg);
- $this->showForm(null, $this->bestNewNickname($display, $sreg));
- }
- }
- }
-
- function message($msg)
- {
- $this->message_text = $msg;
- $this->showPage();
- }
-
- function saveValues($display, $canonical, $sreg)
- {
- common_ensure_session();
- $_SESSION['openid_display'] = $display;
- $_SESSION['openid_canonical'] = $canonical;
- $_SESSION['openid_sreg'] = $sreg;
- }
-
- function getSavedValues()
- {
- return array($_SESSION['openid_display'],
- $_SESSION['openid_canonical'],
- $_SESSION['openid_sreg']);
- }
-
- function createNewUser()
- {
- # FIXME: save invite code before redirect, and check here
-
- if (common_config('site', 'closed')) {
- $this->clientError(_('Registration not allowed.'));
- return;
- }
-
- $invite = null;
-
- if (common_config('site', 'inviteonly')) {
- $code = $_SESSION['invitecode'];
- if (empty($code)) {
- $this->clientError(_('Registration not allowed.'));
- return;
- }
-
- $invite = Invitation::staticGet($code);
-
- if (empty($invite)) {
- $this->clientError(_('Not a valid invitation code.'));
- return;
- }
- }
-
- $nickname = $this->trimmed('newname');
-
- if (!Validate::string($nickname, array('min_length' => 1,
- 'max_length' => 64,
- 'format' => NICKNAME_FMT))) {
- $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
- return;
- }
-
- if (!User::allowed_nickname($nickname)) {
- $this->showForm(_('Nickname not allowed.'));
- return;
- }
-
- if (User::staticGet('nickname', $nickname)) {
- $this->showForm(_('Nickname already in use. Try another one.'));
- return;
- }
-
- list($display, $canonical, $sreg) = $this->getSavedValues();
-
- if (!$display || !$canonical) {
- $this->serverError(_('Stored OpenID not found.'));
- return;
- }
-
- # Possible race condition... let's be paranoid
-
- $other = oid_get_user($canonical);
-
- if ($other) {
- $this->serverError(_('Creating new account for OpenID that already has a user.'));
- return;
- }
-
- $location = '';
- if (!empty($sreg['country'])) {
- if ($sreg['postcode']) {
- # XXX: use postcode to get city and region
- # XXX: also, store postcode somewhere -- it's valuable!
- $location = $sreg['postcode'] . ', ' . $sreg['country'];
- } else {
- $location = $sreg['country'];
- }
- }
-
- if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) {
- $fullname = $sreg['fullname'];
- } else {
- $fullname = '';
- }
-
- if (!empty($sreg['email']) && Validate::email($sreg['email'], true)) {
- $email = $sreg['email'];
- } else {
- $email = '';
- }
-
- # XXX: add language
- # XXX: add timezone
-
- $args = array('nickname' => $nickname,
- 'email' => $email,
- 'fullname' => $fullname,
- 'location' => $location);
-
- if (!empty($invite)) {
- $args['code'] = $invite->code;
- }
-
- $user = User::register($args);
-
- $result = oid_link_user($user->id, $canonical, $display);
-
- oid_set_last($display);
- common_set_user($user);
- common_real_login(true);
- if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
- common_rememberme($user);
- }
- unset($_SESSION['openid_rememberme']);
- common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
- 303);
- }
-
- function connectUser()
- {
- $nickname = $this->trimmed('nickname');
- $password = $this->trimmed('password');
-
- if (!common_check_user($nickname, $password)) {
- $this->showForm(_('Invalid username or password.'));
- return;
- }
-
- # They're legit!
-
- $user = User::staticGet('nickname', $nickname);
-
- list($display, $canonical, $sreg) = $this->getSavedValues();
-
- if (!$display || !$canonical) {
- $this->serverError(_('Stored OpenID not found.'));
- return;
- }
-
- $result = oid_link_user($user->id, $canonical, $display);
-
- if (!$result) {
- $this->serverError(_('Error connecting user to OpenID.'));
- return;
- }
-
- oid_update_user($user, $sreg);
- oid_set_last($display);
- common_set_user($user);
- common_real_login(true);
- if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
- common_rememberme($user);
- }
- unset($_SESSION['openid_rememberme']);
- $this->goHome($user->nickname);
- }
-
- function goHome($nickname)
- {
- $url = common_get_returnto();
- if ($url) {
- # We don't have to return to it again
- common_set_returnto(null);
- } else {
- $url = common_local_url('all',
- array('nickname' =>
- $nickname));
- }
- common_redirect($url, 303);
- }
-
- function bestNewNickname($display, $sreg)
- {
-
- # Try the passed-in nickname
-
- if (!empty($sreg['nickname'])) {
- $nickname = $this->nicknamize($sreg['nickname']);
- if ($this->isNewNickname($nickname)) {
- return $nickname;
- }
- }
-
- # Try the full name
-
- if (!empty($sreg['fullname'])) {
- $fullname = $this->nicknamize($sreg['fullname']);
- if ($this->isNewNickname($fullname)) {
- return $fullname;
- }
- }
-
- # Try the URL
-
- $from_url = $this->openidToNickname($display);
-
- if ($from_url && $this->isNewNickname($from_url)) {
- return $from_url;
- }
-
- # XXX: others?
-
- return null;
- }
-
- function isNewNickname($str)
- {
- if (!Validate::string($str, array('min_length' => 1,
- 'max_length' => 64,
- 'format' => NICKNAME_FMT))) {
- return false;
- }
- if (!User::allowed_nickname($str)) {
- return false;
- }
- if (User::staticGet('nickname', $str)) {
- return false;
- }
- return true;
- }
-
- function openidToNickname($openid)
- {
- if (Auth_Yadis_identifierScheme($openid) == 'XRI') {
- return $this->xriToNickname($openid);
- } else {
- return $this->urlToNickname($openid);
- }
- }
-
- # We try to use an OpenID URL as a legal StatusNet user name in this order
- # 1. Plain hostname, like http://evanp.myopenid.com/
- # 2. One element in path, like http://profile.typekey.com/EvanProdromou/
- # or http://getopenid.com/evanprodromou
-
- function urlToNickname($openid)
- {
- static $bad = array('query', 'user', 'password', 'port', 'fragment');
-
- $parts = parse_url($openid);
-
- # If any of these parts exist, this won't work
-
- foreach ($bad as $badpart) {
- if (array_key_exists($badpart, $parts)) {
- return null;
- }
- }
-
- # We just have host and/or path
-
- # If it's just a host...
- if (array_key_exists('host', $parts) &&
- (!array_key_exists('path', $parts) || strcmp($parts['path'], '/') == 0))
- {
- $hostparts = explode('.', $parts['host']);
-
- # Try to catch common idiom of nickname.service.tld
-
- if ((count($hostparts) > 2) &&
- (strlen($hostparts[count($hostparts) - 2]) > 3) && # try to skip .co.uk, .com.au
- (strcmp($hostparts[0], 'www') != 0))
- {
- return $this->nicknamize($hostparts[0]);
- } else {
- # Do the whole hostname
- return $this->nicknamize($parts['host']);
- }
- } else {
- if (array_key_exists('path', $parts)) {
- # Strip starting, ending slashes
- $path = preg_replace('@/$@', '', $parts['path']);
- $path = preg_replace('@^/@', '', $path);
- if (strpos($path, '/') === false) {
- return $this->nicknamize($path);
- }
- }
- }
-
- return null;
- }
-
- function xriToNickname($xri)
- {
- $base = $this->xriBase($xri);
-
- if (!$base) {
- return null;
- } else {
- # =evan.prodromou
- # or @gratis*evan.prodromou
- $parts = explode('*', substr($base, 1));
- return $this->nicknamize(array_pop($parts));
- }
- }
-
- function xriBase($xri)
- {
- if (substr($xri, 0, 6) == 'xri://') {
- return substr($xri, 6);
- } else {
- return $xri;
- }
- }
-
- # Given a string, try to make it work as a nickname
-
- function nicknamize($str)
- {
- $str = preg_replace('/\W/', '', $str);
- return strtolower($str);
- }
-}
diff --git a/actions/finishremotesubscribe.php b/actions/finishremotesubscribe.php
index 871bc3d2d..b1cec66f4 100644
--- a/actions/finishremotesubscribe.php
+++ b/actions/finishremotesubscribe.php
@@ -1,5 +1,16 @@
<?php
-/*
+/**
+ * Handler for remote subscription finish callback
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@@ -15,285 +26,121 @@
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+ **/
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
+require_once INSTALLDIR.'/lib/omb.php';
+/**
+ * Handler for remote subscription finish callback
+ *
+ * When a remote user subscribes a local user, a redirect to this action is
+ * issued after the remote user authorized his service to subscribe.
+ *
+ * @category Action
+ * @package Laconica
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@controlyourself.ca>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://laconi.ca/
+ */
class FinishremotesubscribeAction extends Action
{
+ /**
+ * Class handler.
+ *
+ * @param array $args query arguments
+ *
+ * @return nothing
+ *
+ **/
function handle($args)
{
-
parent::handle($args);
- if (common_logged_in()) {
- $this->clientError(_('You can use the local subscription!'));
- return;
- }
-
- $omb = $_SESSION['oauth_authorization_request'];
+ /* Restore session data. RemotesubscribeAction should have stored
+ this entry. */
+ $service = unserialize($_SESSION['oauth_authorization_request']);
- if (!$omb) {
+ if (!$service) {
$this->clientError(_('Not expecting this response!'));
return;
}
- common_debug('stored request: '.print_r($omb,true), __FILE__);
-
- common_remove_magic_from_request();
- $req = OAuthRequest::from_request('POST', common_local_url('finishuserauthorization'));
-
- $token = $req->get_parameter('oauth_token');
-
- # I think this is the success metric
-
- if ($token != $omb['token']) {
- $this->clientError(_('Not authorized.'));
- return;
- }
-
- $version = $req->get_parameter('omb_version');
-
- if ($version != OMB_VERSION_01) {
- $this->clientError(_('Unknown version of OMB protocol.'));
- return;
- }
-
- $nickname = $req->get_parameter('omb_listener_nickname');
-
- if (!$nickname) {
- $this->clientError(_('No nickname provided by remote server.'));
- return;
- }
-
- $profile_url = $req->get_parameter('omb_listener_profile');
+ common_debug('stored request: '. print_r($service, true), __FILE__);
- if (!$profile_url) {
- $this->clientError(_('No profile URL returned by server.'));
- return;
- }
-
- if (!Validate::uri($profile_url, array('allowed_schemes' => array('http', 'https')))) {
- $this->clientError(_('Invalid profile URL returned by server.'));
- return;
- }
-
- if ($profile_url == common_local_url('showstream', array('nickname' => $nickname))) {
- $this->clientError(_('You can use the local subscription!'));
- return;
- }
-
- common_debug('listenee: "'.$omb['listenee'].'"', __FILE__);
-
- $user = User::staticGet('nickname', $omb['listenee']);
+ /* Create user objects for both users. Do it early for request
+ validation. */
+ $user = User::staticGet('uri', $service->getListeneeURI());
if (!$user) {
- $this->clientError(_('User being listened to doesn\'t exist.'));
+ $this->clientError(_('User being listened to does not exist.'));
return;
}
- $other = User::staticGet('uri', $omb['listener']);
+ $other = User::staticGet('uri', $service->getListenerURI());
if ($other) {
$this->clientError(_('You can use the local subscription!'));
return;
}
- $fullname = $req->get_parameter('omb_listener_fullname');
- $homepage = $req->get_parameter('omb_listener_homepage');
- $bio = $req->get_parameter('omb_listener_bio');
- $location = $req->get_parameter('omb_listener_location');
- $avatar_url = $req->get_parameter('omb_listener_avatar');
+ $remote = Remote_profile::staticGet('uri', $service->getListenerURI());
- list($newtok, $newsecret) = $this->access_token($omb);
+ $profile = Profile::staticGet($remote->id);
- if (!$newtok || !$newsecret) {
- $this->clientError(_('Couldn\'t convert request tokens to access tokens.'));
+ if ($user->hasBlocked($profile)) {
+ $this->clientError(_('That user has blocked you from subscribing.'));
return;
}
- # XXX: possible attack point; subscribe and return someone else's profile URI
-
- $remote = Remote_profile::staticGet('uri', $omb['listener']);
-
- if ($remote) {
- $exists = true;
- $profile = Profile::staticGet($remote->id);
- $orig_remote = clone($remote);
- $orig_profile = clone($profile);
- # XXX: compare current postNotice and updateProfile URLs to the ones
- # stored in the DB to avoid (possibly...) above attack
- } else {
- $exists = false;
- $remote = new Remote_profile();
- $remote->uri = $omb['listener'];
- $profile = new Profile();
- }
-
- $profile->nickname = $nickname;
- $profile->profileurl = $profile_url;
-
- if (!is_null($fullname)) {
- $profile->fullname = $fullname;
- }
- if (!is_null($homepage)) {
- $profile->homepage = $homepage;
- }
- if (!is_null($bio)) {
- $profile->bio = $bio;
- }
- if (!is_null($location)) {
- $profile->location = $location;
- }
-
- if ($exists) {
- $profile->update($orig_profile);
- } else {
- $profile->created = DB_DataObject_Cast::dateTime(); # current time
- $id = $profile->insert();
- if (!$id) {
- $this->serverError(_('Error inserting new profile'));
+ /* Perform the handling itself via libomb. */
+ try {
+ $service->finishAuthorization();
+ } catch (OAuthException $e) {
+ if ($e->getMessage() == 'The authorized token does not equal the ' .
+ 'submitted token.') {
+ $this->clientError(_('You are not authorized.'));
return;
- }
- $remote->id = $id;
- }
-
- if ($avatar_url) {
- if (!$this->add_avatar($profile, $avatar_url)) {
- $this->serverError(_('Error inserting avatar'));
- return;
- }
- }
-
- $remote->postnoticeurl = $omb['post_notice_url'];
- $remote->updateprofileurl = $omb['update_profile_url'];
-
- if ($exists) {
- if (!$remote->update($orig_remote)) {
- $this->serverError(_('Error updating remote profile'));
+ } else {
+ $this->clientError(_('Could not convert request token to ' .
+ 'access token.'));
return;
}
- } else {
- $remote->created = DB_DataObject_Cast::dateTime(); # current time
- if (!$remote->insert()) {
- $this->serverError(_('Error inserting remote profile'));
- return;
- }
- }
-
- if ($user->hasBlocked($profile)) {
- $this->clientError(_('That user has blocked you from subscribing.'));
+ } catch (OMB_RemoteServiceException $e) {
+ $this->clientError(_('Remote service uses unknown version of ' .
+ 'OMB protocol.'));
+ return;
+ } catch (Exception $e) {
+ common_debug('Got exception ' . print_r($e, true), __FILE__);
+ $this->clientError($e->getMessage());
return;
}
- $sub = new Subscription();
-
- $sub->subscriber = $remote->id;
- $sub->subscribed = $user->id;
-
- $sub_exists = false;
-
- if ($sub->find(true)) {
- $sub_exists = true;
- $orig_sub = clone($sub);
- } else {
- $sub_exists = false;
- $sub->created = DB_DataObject_Cast::dateTime(); # current time
- }
-
- $sub->token = $newtok;
- $sub->secret = $newsecret;
+ /* The service URLs are not accessible from datastore, so setting them
+ after insertion of the profile. */
+ $orig_remote = clone($remote);
- if ($sub_exists) {
- $result = $sub->update($orig_sub);
- } else {
- $result = $sub->insert();
- }
+ $remote->postnoticeurl =
+ $service->getServiceURI(OMB_ENDPOINT_POSTNOTICE);
+ $remote->updateprofileurl =
+ $service->getServiceURI(OMB_ENDPOINT_UPDATEPROFILE);
- if (!$result) {
- common_log_db_error($sub, ($sub_exists) ? 'UPDATE' : 'INSERT', __FILE__);
- $this->clientError(_('Couldn\'t insert new subscription.'));
- return;
+ if (!$remote->update($orig_remote)) {
+ $this->serverError(_('Error updating remote profile'));
+ return;
}
- # Notify user, if necessary
-
- mail_subscribe_notify_profile($user, $profile);
-
- # Clear the data
+ /* Clear the session data. */
unset($_SESSION['oauth_authorization_request']);
- # If we show subscriptions in reverse chron order, this should
- # show up close to the top of the page
-
+ /* If we show subscriptions in reverse chronological order, the new one
+ should show up close to the top of the page. */
common_redirect(common_local_url('subscribers', array('nickname' =>
$user->nickname)),
303);
}
-
- function add_avatar($profile, $url)
- {
- $temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
- copy($url, $temp_filename);
- $imagefile = new ImageFile($profile->id, $temp_filename);
- $filename = Avatar::filename($profile->id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
- return $profile->setOriginal($filename);
- }
-
- function access_token($omb)
- {
-
- common_debug('starting request for access token', __FILE__);
-
- $con = omb_oauth_consumer();
- $tok = new OAuthToken($omb['token'], $omb['secret']);
-
- common_debug('using request token "'.$tok.'"', __FILE__);
-
- $url = $omb['access_token_url'];
-
- common_debug('using access token url "'.$url.'"', __FILE__);
-
- # XXX: Is this the right thing to do? Strip off GET params and make them
- # POST params? Seems wrong to me.
-
- $parsed = parse_url($url);
- $params = array();
- parse_str($parsed['query'], $params);
-
- $req = OAuthRequest::from_consumer_and_token($con, $tok, "POST", $url, $params);
-
- $req->set_parameter('omb_version', OMB_VERSION_01);
-
- # XXX: test to see if endpoint accepts this signature method
-
- $req->sign_request(omb_hmac_sha1(), $con, $tok);
-
- # We re-use this tool's fetcher, since it's pretty good
-
- common_debug('posting to access token url "'.$req->get_normalized_http_url().'"', __FILE__);
- common_debug('posting request data "'.$req->to_postdata().'"', __FILE__);
-
- $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
- $result = $fetcher->post($req->get_normalized_http_url(),
- $req->to_postdata(),
- array('User-Agent: StatusNet/' . STATUSNET_VERSION));
-
- common_debug('got result: "'.print_r($result,true).'"', __FILE__);
-
- if ($result->status != 200) {
- return null;
- }
-
- parse_str($result->body, $return);
-
- return array($return['oauth_token'], $return['oauth_token_secret']);
- }
}
diff --git a/actions/foafgroup.php b/actions/foafgroup.php
new file mode 100644
index 000000000..f5fd7fe88
--- /dev/null
+++ b/actions/foafgroup.php
@@ -0,0 +1,173 @@
+<?php
+/*
+ * StatusNet the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Mail
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Toby Inkster <mail@tobyinkster.co.uk>
+ * @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') && !defined('LACONICA')) { exit(1); }
+
+class FoafGroupAction extends Action
+{
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $nickname_arg = $this->arg('nickname');
+
+ if (empty($nickname_arg)) {
+ $this->clientError(_('No such group.'), 404);
+ return false;
+ }
+
+ $this->nickname = common_canonical_nickname($nickname_arg);
+
+ // Permanent redirect on non-canonical nickname
+
+ if ($nickname_arg != $this->nickname) {
+ common_redirect(common_local_url('foafgroup',
+ array('nickname' => $this->nickname)),
+ 301);
+ return false;
+ }
+
+ $this->group = User_group::staticGet('nickname', $this->nickname);
+
+ if (!$this->group) {
+ $this->clientError(_('No such group.'), 404);
+ return false;
+ }
+
+ common_set_returnto($this->selfUrl());
+
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ header('Content-Type: application/rdf+xml');
+
+ $this->startXML();
+ $this->elementStart('rdf:RDF', array('xmlns:rdf' =>
+ 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+ 'xmlns:dcterms' =>
+ 'http://purl.org/dc/terms/',
+ 'xmlns:sioc' =>
+ 'http://rdfs.org/sioc/ns#',
+ 'xmlns:foaf' =>
+ 'http://xmlns.com/foaf/0.1/',
+ 'xmlns:statusnet' =>
+ 'http://status.net/ont/',
+ 'xmlns' => 'http://xmlns.com/foaf/0.1/'));
+
+ $this->showPpd(common_local_url('foafgroup', array('nickname' => $this->nickname)), $this->group->permalink());
+
+ $this->elementStart('Group', array('rdf:about' =>
+ $this->group->permalink()));
+ if ($this->group->fullname) {
+ $this->element('name', null, $this->group->fullname);
+ }
+ if ($this->group->description) {
+ $this->element('dcterms:description', null, $this->group->description);
+ }
+ if ($this->group->nickname) {
+ $this->element('dcterms:identifier', null, $this->group->nickname);
+ $this->element('nick', null, $this->group->nickname);
+ }
+ foreach ($this->group->getAliases() as $alias) {
+ $this->element('nick', null, $alias);
+ }
+ if ($this->group->homeUrl()) {
+ $this->element('weblog', array('rdf:resource' => $this->group->homeUrl()));
+ }
+ if ($this->group->homepage) {
+ $this->element('page', array('rdf:resource' => $this->group->homepage));
+ }
+ if ($this->group->homepage_logo) {
+ $this->element('depiction', array('rdf:resource' => $this->group->homepage_logo));
+ }
+
+ $members = $this->group->getMembers();
+ $member_details = array();
+ while ($members->fetch()) {
+ $member_uri = common_local_url('userbyid', array('id'=>$members->id));
+ $member_details[$member_uri] = array(
+ 'nickname' => $members->nickname
+ );
+ $this->element('member', array('rdf:resource' => $member_uri));
+ }
+
+ $admins = $this->group->getAdmins();
+ while ($admins->fetch()) {
+ $admin_uri = common_local_url('userbyid', array('id'=>$admins->id));
+ $member_details[$admin_uri]['is_admin'] = true;
+ $this->element('statusnet:groupAdmin', array('rdf:resource' => $admin_uri));
+ }
+
+ $this->elementEnd('Group');
+
+ ksort($member_details);
+ foreach ($member_details as $uri => $details) {
+ if ($details['is_admin'])
+ {
+ $this->elementStart('Agent', array('rdf:about' => $uri));
+ $this->element('nick', null, $details['nickname']);
+ $this->elementStart('holdsAccount');
+ $this->elementStart('sioc:User', array('rdf:about'=>$uri.'#acct'));
+ $this->elementStart('sioc:has_function');
+ $this->elementStart('statusnet:GroupAdminRole');
+ $this->element('sioc:scope', array('rdf:resource' => $this->group->permalink()));
+ $this->elementEnd('statusnet:GroupAdminRole');
+ $this->elementEnd('sioc:has_function');
+ $this->elementEnd('sioc:User');
+ $this->elementEnd('holdsAccount');
+ $this->elementEnd('Agent');
+ }
+ else
+ {
+ $this->element('Agent', array(
+ 'foaf:nick' => $details['nickname'],
+ 'rdf:about' => $uri,
+ ));
+ }
+ }
+
+ $this->elementEnd('rdf:RDF');
+ $this->endXML();
+ }
+
+ function showPpd($foaf_url, $person_uri)
+ {
+ $this->elementStart('Document', array('rdf:about' => $foaf_url));
+ $this->element('primaryTopic', array('rdf:resource' => $person_uri));
+ $this->elementEnd('Document');
+ }
+
+} \ No newline at end of file
diff --git a/actions/groupbyid.php b/actions/groupbyid.php
index 52cfaddfc..f65bf511a 100644
--- a/actions/groupbyid.php
+++ b/actions/groupbyid.php
@@ -68,11 +68,6 @@ class GroupbyidAction extends Action
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
$id = $this->arg('id');
if (!$id) {
diff --git a/actions/groupdesignsettings.php b/actions/groupdesignsettings.php
index cd86e3b05..b87b7d156 100644
--- a/actions/groupdesignsettings.php
+++ b/actions/groupdesignsettings.php
@@ -64,11 +64,6 @@ class GroupDesignSettingsAction extends DesignSettingsAction
{
parent::prepare($args);
- if (!common_config('inboxes', 'enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to edit a group.'));
return false;
diff --git a/actions/grouplogo.php b/actions/grouplogo.php
index 63ba769c7..a9dc7eb1d 100644
--- a/actions/grouplogo.php
+++ b/actions/grouplogo.php
@@ -66,11 +66,6 @@ class GrouplogoAction extends GroupDesignAction
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to create a group.'));
return false;
diff --git a/actions/groupmembers.php b/actions/groupmembers.php
index dcbdd3759..b326a0df7 100644
--- a/actions/groupmembers.php
+++ b/actions/groupmembers.php
@@ -179,9 +179,12 @@ class GroupMemberListItem extends ProfileListItem
function showActions()
{
$this->startActions();
- $this->showSubscribeButton();
- $this->showMakeAdminForm();
- $this->showGroupBlockForm();
+ if (Event::handle('StartProfileListItemActionElements', array($this))) {
+ $this->showSubscribeButton();
+ $this->showMakeAdminForm();
+ $this->showGroupBlockForm();
+ Event::handle('EndProfileListItemActionElements', array($this));
+ }
$this->endActions();
}
diff --git a/actions/grouprss.php b/actions/grouprss.php
index 70c1ded48..50e48a67e 100644
--- a/actions/grouprss.php
+++ b/actions/grouprss.php
@@ -76,11 +76,6 @@ class groupRssAction extends Rss10Action
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
$nickname_arg = $this->arg('nickname');
$nickname = common_canonical_nickname($nickname_arg);
@@ -104,6 +99,7 @@ class groupRssAction extends Rss10Action
return false;
}
+ $this->notices = $this->getNotices($this->limit);
return true;
}
diff --git a/actions/groupsearch.php b/actions/groupsearch.php
index 517f12789..55f4cee62 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 9fa6a76f6..788130c58 100644
--- a/actions/invite.php
+++ b/actions/invite.php
@@ -241,7 +241,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/joingroup.php b/actions/joingroup.php
index 0209dd43f..bf69b2ad1 100644
--- a/actions/joingroup.php
+++ b/actions/joingroup.php
@@ -56,11 +56,6 @@ class JoingroupAction extends Action
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to join a group.'));
return false;
diff --git a/actions/leavegroup.php b/actions/leavegroup.php
index 60b22e147..08fce1509 100644
--- a/actions/leavegroup.php
+++ b/actions/leavegroup.php
@@ -56,11 +56,6 @@ class LeavegroupAction extends Action
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work.'));
- return false;
- }
-
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to leave a group.'));
return false;
diff --git a/actions/login.php b/actions/login.php
index ac8c40c3e..f6d016310 100644
--- a/actions/login.php
+++ b/actions/login.php
@@ -67,8 +67,6 @@ class LoginAction extends Action
*
* Switches on request method; either shows the form or handles its input.
*
- * Checks if only OpenID is allowed and redirects to openidlogin if so.
- *
* @param array $args $_REQUEST data
*
* @return void
@@ -77,9 +75,7 @@ class LoginAction extends Action
function handle($args)
{
parent::handle($args);
- if (common_config('site', 'openidonly')) {
- common_redirect(common_local_url('openidlogin'));
- } else if (common_is_real_login()) {
+ if (common_is_real_login()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->checkLogin();
@@ -259,11 +255,6 @@ class LoginAction extends Action
return _('For security reasons, please re-enter your ' .
'user name and password ' .
'before changing your settings.');
- } else if (common_config('openid', 'enabled')) {
- return _('Login with your username and password. ' .
- 'Don\'t have a username yet? ' .
- '[Register](%%action.register%%) a new account, or ' .
- 'try [OpenID](%%action.openidlogin%%). ');
} else {
return _('Login with your username and password. ' .
'Don\'t have a username yet? ' .
diff --git a/actions/logout.php b/actions/logout.php
index 298b2a484..1e0adae57 100644
--- a/actions/logout.php
+++ b/actions/logout.php
@@ -32,8 +32,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once INSTALLDIR.'/lib/openid.php';
-
/**
* Logout action class.
*
diff --git a/actions/newgroup.php b/actions/newgroup.php
index 01cb636aa..80da9861a 100644
--- a/actions/newgroup.php
+++ b/actions/newgroup.php
@@ -61,11 +61,6 @@ class NewgroupAction extends Action
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to create a group.'));
return false;
@@ -146,8 +141,8 @@ class NewgroupAction extends Action
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
- } else if (!is_null($description) && mb_strlen($description) > 140) {
- $this->showForm(_('description is too long (max 140 chars).'));
+ } else if (User_group::descriptionTooLong($description)) {
+ $this->showForm(sprintf(_('description is too long (max %d chars).'), User_group::maxDescription()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));
diff --git a/actions/newmessage.php b/actions/newmessage.php
index 828a339cf..a0b17fc18 100644
--- a/actions/newmessage.php
+++ b/actions/newmessage.php
@@ -144,9 +144,10 @@ class NewmessageAction extends Action
} else {
$content_shortened = common_shorten_links($this->content);
- if (mb_strlen($content_shortened) > 140) {
- $this->showForm(_('That\'s too long. ' .
- 'Max message size is 140 chars.'));
+ if (Message::contentTooLong($content_shortened)) {
+ $this->showForm(sprintf(_('That\'s too long. ' .
+ 'Max message size is %d chars.'),
+ Message::maxContent()));
return;
}
}
diff --git a/actions/newnotice.php b/actions/newnotice.php
index 8c0476f70..9ee031f93 100644
--- a/actions/newnotice.php
+++ b/actions/newnotice.php
@@ -162,9 +162,10 @@ class NewnoticeAction extends Action
$this->clientError(_('No content!'));
} else {
$content_shortened = common_shorten_links($content);
- if (mb_strlen($content_shortened) > 140) {
- $this->clientError(_('That\'s too long. '.
- 'Max notice size is 140 chars.'));
+ if (Notice::contentTooLong($content_shortened)) {
+ $this->clientError(sprintf(_('That\'s too long. '.
+ 'Max notice size is %d chars.'),
+ Notice::maxContent()));
}
}
@@ -245,9 +246,10 @@ class NewnoticeAction extends Action
}
$content_shortened .= ' ' . $short_fileurl;
- if (mb_strlen($content_shortened) > 140) {
+ if (Notice::contentTooLong($content_shortened)) {
$this->deleteFile($filename);
- $this->clientError(_('Max notice size is 140 chars, including attachment URL.'));
+ $this->clientError(sprintf(_('Max notice size is %d chars, including attachment URL.'),
+ Notice::maxContent()));
}
// Also, not sure this is necessary -- Zach
@@ -257,13 +259,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/noticesearch.php b/actions/noticesearch.php
index 69dcd1a46..79cf572cc 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/openidlogin.php b/actions/openidlogin.php
deleted file mode 100644
index 9b7deefb6..000000000
--- a/actions/openidlogin.php
+++ /dev/null
@@ -1,139 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-require_once(INSTALLDIR.'/lib/openid.php');
-
-class OpenidloginAction extends Action
-{
- function handle($args)
- {
- parent::handle($args);
- if (!common_config('openid', 'enabled')) {
- common_redirect(common_local_url('login'));
- } else if (common_is_real_login()) {
- $this->clientError(_('Already logged in.'));
- } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $openid_url = $this->trimmed('openid_url');
-
- # CSRF protection
- $token = $this->trimmed('token');
- if (!$token || $token != common_session_token()) {
- $this->showForm(_('There was a problem with your session token. Try again, please.'), $openid_url);
- return;
- }
-
- $rememberme = $this->boolean('rememberme');
-
- common_ensure_session();
-
- $_SESSION['openid_rememberme'] = $rememberme;
-
- $result = oid_authenticate($openid_url,
- 'finishopenidlogin');
-
- if (is_string($result)) { # error message
- unset($_SESSION['openid_rememberme']);
- $this->showForm($result, $openid_url);
- }
- } else {
- $openid_url = oid_get_last();
- $this->showForm(null, $openid_url);
- }
- }
-
- function getInstructions()
- {
- if (common_logged_in() && !common_is_real_login() &&
- common_get_returnto()) {
- // rememberme logins have to reauthenticate before
- // changing any profile settings (cookie-stealing protection)
- return _('For security reasons, please re-login with your ' .
- '[OpenID](%%doc.openid%%) ' .
- 'before changing your settings.');
- } else {
- return _('Login with an [OpenID](%%doc.openid%%) account.');
- }
- }
-
- function showPageNotice()
- {
- if ($this->error) {
- $this->element('div', array('class' => 'error'), $this->error);
- } else {
- $instr = $this->getInstructions();
- $output = common_markup_to_html($instr);
- $this->elementStart('div', 'instructions');
- $this->raw($output);
- $this->elementEnd('div');
- }
- }
-
- function showScripts()
- {
- parent::showScripts();
- $this->autofocus('openid_url');
- }
-
- function title()
- {
- return _('OpenID Login');
- }
-
- function showForm($error=null, $openid_url)
- {
- $this->error = $error;
- $this->openid_url = $openid_url;
- $this->showPage();
- }
-
- function showContent() {
- $formaction = common_local_url('openidlogin');
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_openid_login',
- 'class' => 'form_settings',
- 'action' => $formaction));
- $this->elementStart('fieldset');
- $this->element('legend', null, _('OpenID login'));
- $this->hidden('token', common_session_token());
-
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $this->input('openid_url', _('OpenID URL'),
- $this->openid_url,
- _('Your OpenID URL'));
- $this->elementEnd('li');
- $this->elementStart('li', array('id' => 'settings_rememberme'));
- $this->checkbox('rememberme', _('Remember me'), false,
- _('Automatically login in the future; ' .
- 'not for shared computers!'));
- $this->elementEnd('li');
- $this->elementEnd('ul');
- $this->submit('submit', _('Login'));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- }
-
- function showLocalNav()
- {
- $nav = new LoginGroupNav($this);
- $nav->show();
- }
-}
diff --git a/actions/openidsettings.php b/actions/openidsettings.php
deleted file mode 100644
index 30725fc1b..000000000
--- a/actions/openidsettings.php
+++ /dev/null
@@ -1,246 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Settings for OpenID
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @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.'/lib/accountsettingsaction.php';
-require_once INSTALLDIR.'/lib/openid.php';
-
-/**
- * Settings for OpenID
- *
- * Lets users add, edit and delete OpenIDs from their account
- *
- * @category Settings
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-class OpenidsettingsAction extends AccountSettingsAction
-{
- /**
- * Title of the page
- *
- * @return string Page title
- */
-
- function title()
- {
- return _('OpenID settings');
- }
-
- /**
- * Instructions for use
- *
- * @return string Instructions for use
- */
-
- function getInstructions()
- {
- return _('[OpenID](%%doc.openid%%) lets you log into many sites' .
- ' with the same user account.'.
- ' Manage your associated OpenIDs from here.');
- }
-
- function showScripts()
- {
- parent::showScripts();
- $this->autofocus('openid_url');
- }
-
- /**
- * Show the form for OpenID management
- *
- * We have one form with a few different submit buttons to do different things.
- *
- * @return void
- */
-
- function showContent()
- {
- if (!common_config('openid', 'enabled')) {
- $this->element('div', array('class' => 'error'),
- _('OpenID is not available.'));
- return;
- }
-
- $user = common_current_user();
-
- $this->elementStart('form', array('method' => 'post',
- 'id' => 'form_settings_openid_add',
- 'class' => 'form_settings',
- 'action' =>
- common_local_url('openidsettings')));
- $this->elementStart('fieldset', array('id' => 'settings_openid_add'));
- $this->element('legend', null, _('Add OpenID'));
- $this->hidden('token', common_session_token());
- $this->element('p', 'form_guide',
- _('If you want to add an OpenID to your account, ' .
- 'enter it in the box below and click "Add".'));
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $this->element('label', array('for' => 'openid_url'),
- _('OpenID URL'));
- $this->element('input', array('name' => 'openid_url',
- 'type' => 'text',
- 'id' => 'openid_url'));
- $this->elementEnd('li');
- $this->elementEnd('ul');
- $this->element('input', array('type' => 'submit',
- 'id' => 'settings_openid_add_action-submit',
- 'name' => 'add',
- 'class' => 'submit',
- 'value' => _('Add')));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
-
- $oid = new User_openid();
-
- $oid->user_id = $user->id;
-
- $cnt = $oid->find();
-
- if ($cnt > 0) {
-
- $this->element('h2', null, _('Remove OpenID'));
-
- if ($cnt == 1 && !$user->password) {
-
- $this->element('p', 'form_guide',
- _('Removing your only OpenID '.
- 'would make it impossible to log in! ' .
- 'If you need to remove it, '.
- 'add another OpenID first.'));
-
- if ($oid->fetch()) {
- $this->elementStart('p');
- $this->element('a', array('href' => $oid->canonical),
- $oid->display);
- $this->elementEnd('p');
- }
-
- } else {
-
- $this->element('p', 'form_guide',
- _('You can remove an OpenID from your account '.
- 'by clicking the button marked "Remove".'));
- $idx = 0;
-
- while ($oid->fetch()) {
- $this->elementStart('form',
- array('method' => 'POST',
- 'id' => 'form_settings_openid_delete' . $idx,
- 'class' => 'form_settings',
- 'action' =>
- common_local_url('openidsettings')));
- $this->elementStart('fieldset');
- $this->hidden('token', common_session_token());
- $this->element('a', array('href' => $oid->canonical),
- $oid->display);
- $this->element('input', array('type' => 'hidden',
- 'id' => 'openid_url'.$idx,
- 'name' => 'openid_url',
- 'value' => $oid->canonical));
- $this->element('input', array('type' => 'submit',
- 'id' => 'remove'.$idx,
- 'name' => 'remove',
- 'class' => 'submit remove',
- 'value' => _('Remove')));
- $this->elementEnd('fieldset');
- $this->elementEnd('form');
- $idx++;
- }
- }
- }
- }
-
- /**
- * Handle a POST request
- *
- * Muxes to different sub-functions based on which button was pushed
- *
- * @return void
- */
-
- function handlePost()
- {
- // CSRF protection
- $token = $this->trimmed('token');
- if (!$token || $token != common_session_token()) {
- $this->showForm(_('There was a problem with your session token. '.
- 'Try again, please.'));
- return;
- }
-
- if ($this->arg('add')) {
- $result = oid_authenticate($this->trimmed('openid_url'),
- 'finishaddopenid');
- if (is_string($result)) { // error message
- $this->showForm($result);
- }
- } else if ($this->arg('remove')) {
- $this->removeOpenid();
- } else {
- $this->showForm(_('Something weird happened.'));
- }
- }
-
- /**
- * Handles a request to remove an OpenID from the user's account
- *
- * Validates input and, if everything is OK, deletes the OpenID.
- * Reloads the form with a success or error notification.
- *
- * @return void
- */
-
- function removeOpenid()
- {
- $openid_url = $this->trimmed('openid_url');
-
- $oid = User_openid::staticGet('canonical', $openid_url);
-
- if (!$oid) {
- $this->showForm(_('No such OpenID.'));
- return;
- }
- $cur = common_current_user();
- if (!$cur || $oid->user_id != $cur->id) {
- $this->showForm(_('That OpenID does not belong to you.'));
- return;
- }
- $oid->delete();
- $this->showForm(_('OpenID removed.'), true);
- return;
- }
-}
diff --git a/actions/othersettings.php b/actions/othersettings.php
index f898e2207..011b4fc83 100644
--- a/actions/othersettings.php
+++ b/actions/othersettings.php
@@ -97,19 +97,20 @@ class OthersettingsAction extends AccountSettingsAction
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
- // I18N
-
- $services = array(
- '' => 'None',
- 'ur1.ca' => 'ur1.ca (free service)',
- '2tu.us' => '2tu.us (free service)',
- 'ptiturl.com' => 'ptiturl.com',
- 'bit.ly' => 'bit.ly',
- 'tinyurl.com' => 'tinyurl.com',
- 'is.gd' => 'is.gd',
- 'snipr.com' => 'snipr.com',
- 'metamark.net' => 'metamark.net'
- );
+ $services=array();
+ global $_shorteners;
+ if($_shorteners){
+ foreach($_shorteners as $name=>$value)
+ {
+ $services[$name]=$name;
+ if($value['info']['freeService']){
+ // I18N
+ $services[$name].=' (free service)';
+ }
+ }
+ }
+ asort($services);
+ $services['']='None';
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
diff --git a/actions/postnotice.php b/actions/postnotice.php
index e775ca17e..c2e1c44ca 100644
--- a/actions/postnotice.php
+++ b/actions/postnotice.php
@@ -1,5 +1,16 @@
<?php
-/*
+/**
+ * Handle postnotice action
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@@ -19,73 +30,67 @@
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
+/**
+ * Handler for postnotice action
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
class PostnoticeAction extends Action
{
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+ try {
+ $this->checkNotice();
+ } catch (Exception $e) {
+ $this->clientError($e->getMessage());
+ return false;
+ }
+ return true;
+ }
+
function handle($args)
{
parent::handle($args);
try {
- common_remove_magic_from_request();
- $req = OAuthRequest::from_request('POST', common_local_url('postnotice'));
- # Note: server-to-server function!
- $server = omb_oauth_server();
- list($consumer, $token) = $server->verify_request($req);
- if ($this->save_notice($req, $consumer, $token)) {
- print "omb_version=".OMB_VERSION_01;
- }
- } catch (OAuthException $e) {
+ $srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
+ omb_oauth_server());
+ $srv->handlePostNotice();
+ } catch (Exception $e) {
$this->serverError($e->getMessage());
return;
}
}
- function save_notice(&$req, &$consumer, &$token)
+ function checkNotice()
{
- $version = $req->get_parameter('omb_version');
- if ($version != OMB_VERSION_01) {
- $this->clientError(_('Unsupported OMB version'), 400);
- return false;
- }
- # First, check to see
- $listenee = $req->get_parameter('omb_listenee');
- $remote_profile = Remote_profile::staticGet('uri', $listenee);
- if (!$remote_profile) {
- $this->clientError(_('Profile unknown'), 403);
- return false;
- }
- $sub = Subscription::staticGet('token', $token->key);
- if (!$sub) {
- $this->clientError(_('No such subscription'), 403);
- return false;
- }
- $content = $req->get_parameter('omb_notice_content');
- $content_shortened = common_shorten_links($content);
- if (mb_strlen($content_shortened) > 140) {
+ $content = common_shorten_links($_POST['omb_notice_content']);
+ if (Notice::contentTooLong($content)) {
$this->clientError(_('Invalid notice content'), 400);
return false;
}
- $notice_uri = $req->get_parameter('omb_notice');
- if (!Validate::uri($notice_uri) &&
- !common_valid_tag($notice_uri)) {
- $this->clientError(_('Invalid notice uri'), 400);
- return false;
- }
- $notice_url = $req->get_parameter('omb_notice_url');
- if ($notice_url && !common_valid_http_url($notice_url)) {
- $this->clientError(_('Invalid notice url'), 400);
- return false;
+ $license = $_POST['omb_notice_license'];
+ $site_license = common_config('license', 'url');
+ if ($license && !common_compatible_license($license, $site_license)) {
+ throw new Exception(sprintf(_('Notice license ‘%s’ is not ' .
+ 'compatible with site license ‘%s’.'),
+ $license, $site_license));
}
- $notice = Notice::staticGet('uri', $notice_uri);
- if (!$notice) {
- $notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri);
- if (is_string($notice)) {
- common_server_serror($notice, 500);
- return false;
- }
- common_broadcast_notice($notice, true);
- }
- return true;
}
}
+?> \ No newline at end of file
diff --git a/actions/profilesettings.php b/actions/profilesettings.php
index 2d66e9946..5445d9bb2 100644
--- a/actions/profilesettings.php
+++ b/actions/profilesettings.php
@@ -117,9 +117,16 @@ class ProfilesettingsAction extends AccountSettingsAction
_('URL of your homepage, blog, or profile on another site'));
$this->elementEnd('li');
$this->elementStart('li');
+ $maxBio = Profile::maxBio();
+ if ($maxBio > 0) {
+ $bioInstr = sprintf(_('Describe yourself and your interests in %d chars'),
+ $maxBio);
+ } else {
+ $bioInstr = _('Describe yourself and your interests');
+ }
$this->textarea('bio', _('Bio'),
($this->arg('bio')) ? $this->arg('bio') : $profile->bio,
- _('Describe yourself and your interests in 140 chars'));
+ $bioInstr);
$this->elementEnd('li');
$this->elementStart('li');
$this->input('location', _('Location'),
@@ -210,8 +217,9 @@ class ProfilesettingsAction extends AccountSettingsAction
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
- } else if (!is_null($bio) && mb_strlen($bio) > 140) {
- $this->showForm(_('Bio is too long (max 140 chars).'));
+ } else if (Profile::bioTooLong($bio)) {
+ $this->showForm(sprintf(_('Bio is too long (max %d chars).'),
+ Profile::maxBio()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));
diff --git a/actions/public.php b/actions/public.php
index d426648f3..73fad182a 100644
--- a/actions/public.php
+++ b/actions/public.php
@@ -114,8 +114,6 @@ class PublicAction extends Action
{
parent::handle($args);
- header('X-XRDS-Location: '. common_local_url('publicxrds'));
-
$this->showPage();
}
@@ -157,22 +155,6 @@ class PublicAction extends Action
}
/**
- * Extra head elements
- *
- * We include a <meta> element linking to the publicxrds page, for OpenID
- * client-side authentication.
- *
- * @return void
- */
-
- function extraHead()
- {
- // for client side of OpenID authentication
- $this->element('meta', array('http-equiv' => 'X-XRDS-Location',
- 'content' => common_local_url('publicxrds')));
- }
-
- /**
* Show tabset for this page
*
* Uses the PublicGroupNav widget
@@ -196,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!');
}
}
@@ -244,11 +225,10 @@ 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 [StatusNet](http://status.net/) 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 [StatusNet](http://status.net/) 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 [StatusNet](http://status.net/) tool.');
diff --git a/actions/publicrss.php b/actions/publicrss.php
index 593888b9f..0c5d061cb 100644
--- a/actions/publicrss.php
+++ b/actions/publicrss.php
@@ -50,8 +50,22 @@ require_once INSTALLDIR.'/lib/rssaction.php';
class PublicrssAction extends Rss10Action
{
/**
+ * Read arguments and initialize members
+ *
+ * @param array $args Arguments from $_REQUEST
+ * @return boolean success
+ */
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->notices = $this->getNotices($this->limit);
+ return true;
+ }
+
+ /**
* Initialization.
- *
+ *
* @return boolean true
*/
function init()
@@ -73,7 +87,7 @@ class PublicrssAction extends Rss10Action
while ($notice->fetch()) {
$notices[] = clone($notice);
}
-
+
return $notices;
}
diff --git a/actions/publictagcloud.php b/actions/publictagcloud.php
index 60bb53e27..e7f6ee36c 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/publicxrds.php b/actions/publicxrds.php
deleted file mode 100644
index 209a10e3d..000000000
--- a/actions/publicxrds.php
+++ /dev/null
@@ -1,122 +0,0 @@
-<?php
-
-/**
- * Public XRDS for OpenID
- *
- * PHP version 5
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/openid.php';
-
-/**
- * Public XRDS for OpenID
- *
- * @category Action
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @author Robin Millette <millette@status.net>
- * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://status.net/
- *
- * @todo factor out similarities with XrdsAction
- */
-class PublicxrdsAction extends Action
-{
- /**
- * Is read only?
- *
- * @return boolean true
- */
- function isReadOnly($args)
- {
- return true;
- }
-
- /**
- * Class handler.
- *
- * @param array $args array of arguments
- *
- * @return nothing
- */
- function handle($args)
- {
- parent::handle($args);
- header('Content-Type: application/xrds+xml');
- $this->startXML();
- $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
- $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
- 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
- 'version' => '2.0'));
- $this->element('Type', null, 'xri://$xrds*simple');
- foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) {
- $this->showService(Auth_OpenID_RP_RETURN_TO_URL_TYPE,
- common_local_url($finish));
- }
- $this->elementEnd('XRD');
- $this->elementEnd('XRDS');
- $this->endXML();
- }
-
- /**
- * Show service.
- *
- * @param string $type XRDS type
- * @param string $uri URI
- * @param array $params type parameters, null by default
- * @param array $sigs type signatures, null by default
- * @param string $localId local ID, null by default
- *
- * @return void
- */
- function showService($type, $uri, $params=null, $sigs=null, $localId=null)
- {
- $this->elementStart('Service');
- if ($uri) {
- $this->element('URI', null, $uri);
- }
- $this->element('Type', null, $type);
- if ($params) {
- foreach ($params as $param) {
- $this->element('Type', null, $param);
- }
- }
- if ($sigs) {
- foreach ($sigs as $sig) {
- $this->element('Type', null, $sig);
- }
- }
- if ($localId) {
- $this->element('LocalID', null, $localId);
- }
- $this->elementEnd('Service');
- }
-}
-
diff --git a/actions/register.php b/actions/register.php
index eefbc340a..100ab7424 100644
--- a/actions/register.php
+++ b/actions/register.php
@@ -116,8 +116,6 @@ class RegisterAction extends Action
*
* Checks if registration is closed and shows an error if so.
*
- * Checks if only OpenID is allowed and redirects to openidlogin if so.
- *
* @param array $args $_REQUEST data
*
* @return void
@@ -129,8 +127,6 @@ class RegisterAction extends Action
if (common_config('site', 'closed')) {
$this->clientError(_('Registration not allowed.'));
- } else if (common_config('site', 'openidonly')) {
- common_redirect(common_local_url('openidlogin'));
} else if (common_logged_in()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
@@ -217,8 +213,9 @@ class RegisterAction extends Action
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
$this->showForm(_('Full name is too long (max 255 chars).'));
return;
- } else if (!is_null($bio) && mb_strlen($bio) > 140) {
- $this->showForm(_('Bio is too long (max 140 chars).'));
+ } else if (Profile::bioTooLong($bio)) {
+ $this->showForm(sprintf(_('Bio is too long (max %d chars).'),
+ Profile::maxBio()));
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
$this->showForm(_('Location is too long (max 255 chars).'));
@@ -335,22 +332,11 @@ class RegisterAction extends Action
} else if ($this->error) {
$this->element('p', 'error', $this->error);
} else {
- if (common_config('openid', 'enabled')) {
- $instr =
- common_markup_to_html(_('With this form you can create '.
- ' a new account. ' .
- 'You can then post notices and '.
- 'link up to friends and colleagues. '.
- '(Have an [OpenID](http://openid.net/)? ' .
- 'Try our [OpenID registration]'.
- '(%%action.openidlogin%%)!)'));
- } else {
- $instr =
- common_markup_to_html(_('With this form you can create '.
- ' a new account. ' .
- 'You can then post notices and '.
- 'link up to friends and colleagues.'));
- }
+ $instr =
+ common_markup_to_html(_('With this form you can create '.
+ ' a new account. ' .
+ 'You can then post notices and '.
+ 'link up to friends and colleagues. '));
$this->elementStart('div', 'instructions');
$this->raw($instr);
@@ -463,10 +449,16 @@ class RegisterAction extends Action
'or profile on another site'));
$this->elementEnd('li');
$this->elementStart('li');
+ $maxBio = Profile::maxBio();
+ if ($maxBio > 0) {
+ $bioInstr = sprintf(_('Describe yourself and your interests in %d chars'),
+ $maxBio);
+ } else {
+ $bioInstr = _('Describe yourself and your interests');
+ }
$this->textarea('bio', _('Bio'),
$this->trimmed('bio'),
- _('Describe yourself and your '.
- 'interests in 140 chars'));
+ $bioInstr);
$this->elementEnd('li');
$this->elementStart('li');
$this->input('location', _('Location'),
diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php
index 374392d4a..aee2a5d8e 100644
--- a/actions/remotesubscribe.php
+++ b/actions/remotesubscribe.php
@@ -1,5 +1,16 @@
<?php
-/*
+/**
+ * Handler for remote subscription
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@@ -15,11 +26,24 @@
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+ **/
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
+require_once INSTALLDIR.'/extlib/libomb/profile.php';
+
+/**
+ * Handler for remote subscription
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
class RemotesubscribeAction extends Action
{
@@ -36,7 +60,7 @@ class RemotesubscribeAction extends Action
return false;
}
- $this->nickname = $this->trimmed('nickname');
+ $this->nickname = $this->trimmed('nickname');
$this->profile_url = $this->trimmed('profile_url');
return true;
@@ -47,7 +71,7 @@ class RemotesubscribeAction extends Action
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- # CSRF protection
+ /* Use a session token for CSRF protection. */
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->showForm(_('There was a problem with your session token. '.
@@ -71,13 +95,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);
@@ -92,8 +114,8 @@ class RemotesubscribeAction extends Action
function showContent()
{
- # id = remotesubscribe conflicts with the
- # button on profile page
+ /* The id 'remotesubscribe' conflicts with the
+ button on profile page. */
$this->elementStart('form', array('id' => 'form_remote_subscribe',
'method' => 'post',
'class' => 'form_settings',
@@ -119,247 +141,50 @@ class RemotesubscribeAction extends Action
function remoteSubscription()
{
- $user = $this->getUser();
-
- if (!$user) {
+ if (!$this->nickname) {
$this->showForm(_('No such user.'));
return;
}
+ $user = User::staticGet('nickname', $this->nickname);
+
$this->profile_url = $this->trimmed('profile_url');
if (!$this->profile_url) {
- $this->showForm(_('No such user.'));
+ $this->showForm(_('No such user'));
return;
}
- if (!Validate::uri($this->profile_url, array('allowed_schemes' => array('http', 'https')))) {
+ if (!common_valid_http_url($this->profile_url)) {
$this->showForm(_('Invalid profile URL (bad format)'));
return;
}
- $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
- $yadis = Auth_Yadis_Yadis::discover($this->profile_url, $fetcher);
-
- if (!$yadis || $yadis->failed) {
- $this->showForm(_('Not a valid profile URL (no YADIS document).'));
- return;
- }
-
- # XXX: a little liberal for sites that accidentally put whitespace before the xml declaration
-
- $xrds =& Auth_Yadis_XRDS::parseXRDS(trim($yadis->response_text));
-
- if (!$xrds) {
- $this->showForm(_('Not a valid profile URL (no XRDS defined).'));
- return;
- }
-
- $omb = $this->getOmb($xrds);
-
- if (!$omb) {
- $this->showForm(_('Not a valid profile URL (incorrect services).'));
- return;
- }
-
- if (omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]) ==
- common_local_url('requesttoken'))
- {
- $this->showForm(_('That\'s a local profile! Login to subscribe.'));
+ try {
+ $service = new OMB_Service_Consumer($this->profile_url,
+ common_root_url(),
+ omb_oauth_datastore());
+ } catch (OMB_InvalidYadisException $e) {
+ $this->showForm(_('Not a valid profile URL (no YADIS document or ' .
+ 'no or invalid XRDS defined).'));
return;
}
- if (User::staticGet('uri', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]))) {
- $this->showForm(_('That\'s a local profile! Login to subscribe.'));
+ if ($service->getServiceURI(OAUTH_ENDPOINT_REQUEST) ==
+ common_local_url('requesttoken') ||
+ User::staticGet('uri', $service->getRemoteUserURI())) {
+ $this->showForm(_('That’s a local profile! Login to subscribe.'));
return;
}
- list($token, $secret) = $this->requestToken($omb);
-
- if (!$token || !$secret) {
- $this->showForm(_('Couldn\'t get a request token.'));
+ try {
+ $service->requestToken();
+ } catch (OMB_RemoteServiceException $e) {
+ $this->showForm(_('Couldn’t get a request token.'));
return;
}
- $this->requestAuthorization($user, $omb, $token, $secret);
- }
-
- function getUser()
- {
- $user = null;
- if ($this->nickname) {
- $user = User::staticGet('nickname', $this->nickname);
- }
- return $user;
- }
-
- function getOmb($xrds)
- {
- static $omb_endpoints = array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE);
- static $oauth_endpoints = array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE,
- OAUTH_ENDPOINT_ACCESS);
- $omb = array();
-
- # XXX: the following code could probably be refactored to eliminate dupes
-
- $oauth_services = omb_get_services($xrds, OAUTH_DISCOVERY);
-
- if (!$oauth_services) {
- return null;
- }
-
- $oauth_service = $oauth_services[0];
-
- $oauth_xrd = $this->getXRD($oauth_service, $xrds);
-
- if (!$oauth_xrd) {
- return null;
- }
-
- if (!$this->addServices($oauth_xrd, $oauth_endpoints, $omb)) {
- return null;
- }
-
- $omb_services = omb_get_services($xrds, OMB_NAMESPACE);
-
- if (!$omb_services) {
- return null;
- }
-
- $omb_service = $omb_services[0];
-
- $omb_xrd = $this->getXRD($omb_service, $xrds);
-
- if (!$omb_xrd) {
- return null;
- }
-
- if (!$this->addServices($omb_xrd, $omb_endpoints, $omb)) {
- return null;
- }
-
- # XXX: check that we got all the services we needed
-
- foreach (array_merge($omb_endpoints, $oauth_endpoints) as $type) {
- if (!array_key_exists($type, $omb) || !$omb[$type]) {
- return null;
- }
- }
-
- if (!omb_local_id($omb[OAUTH_ENDPOINT_REQUEST])) {
- return null;
- }
-
- return $omb;
- }
-
- function getXRD($main_service, $main_xrds)
- {
- $uri = omb_service_uri($main_service);
- if (strpos($uri, "#") !== 0) {
- # FIXME: more rigorous handling of external service definitions
- return null;
- }
- $id = substr($uri, 1);
- $nodes = $main_xrds->allXrdNodes;
- $parser = $main_xrds->parser;
- foreach ($nodes as $node) {
- $attrs = $parser->attributes($node);
- if (array_key_exists('xml:id', $attrs) &&
- $attrs['xml:id'] == $id) {
- # XXX: trick the constructor into thinking this is the only node
- $bogus_nodes = array($node);
- return new Auth_Yadis_XRDS($parser, $bogus_nodes);
- }
- }
- return null;
- }
-
- function addServices($xrd, $types, &$omb)
- {
- foreach ($types as $type) {
- $matches = omb_get_services($xrd, $type);
- if ($matches) {
- $omb[$type] = $matches[0];
- } else {
- # no match for type
- return false;
- }
- }
- return true;
- }
-
- function requestToken($omb)
- {
- $con = omb_oauth_consumer();
-
- $url = omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]);
-
- # XXX: Is this the right thing to do? Strip off GET params and make them
- # POST params? Seems wrong to me.
-
- $parsed = parse_url($url);
- $params = array();
- parse_str($parsed['query'], $params);
-
- $req = OAuthRequest::from_consumer_and_token($con, null, "POST", $url, $params);
-
- $listener = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]);
-
- if (!$listener) {
- return null;
- }
-
- $req->set_parameter('omb_listener', $listener);
- $req->set_parameter('omb_version', OMB_VERSION_01);
-
- # XXX: test to see if endpoint accepts this signature method
-
- $req->sign_request(omb_hmac_sha1(), $con, null);
-
- # We re-use this tool's fetcher, since it's pretty good
-
- $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
-
- $result = $fetcher->post($req->get_normalized_http_url(),
- $req->to_postdata(),
- array('User-Agent: StatusNet/' . STATUSNET_VERSION));
- if ($result->status != 200) {
- return null;
- }
-
- parse_str($result->body, $return);
-
- return array($return['oauth_token'], $return['oauth_token_secret']);
- }
-
- function requestAuthorization($user, $omb, $token, $secret)
- {
- $con = omb_oauth_consumer();
- $tok = new OAuthToken($token, $secret);
-
- $url = omb_service_uri($omb[OAUTH_ENDPOINT_AUTHORIZE]);
-
- # XXX: Is this the right thing to do? Strip off GET params and make them
- # POST params? Seems wrong to me.
-
- $parsed = parse_url($url);
- $params = array();
- parse_str($parsed['query'], $params);
-
- $req = OAuthRequest::from_consumer_and_token($con, $tok, 'GET', $url, $params);
-
- # We send over a ton of information. This lets the other
- # server store info about our user, and it lets the current
- # user decide if they really want to authorize the subscription.
-
- $req->set_parameter('omb_version', OMB_VERSION_01);
- $req->set_parameter('omb_listener', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]));
- $req->set_parameter('omb_listenee', $user->uri);
- $req->set_parameter('omb_listenee_profile', common_profile_url($user->nickname));
- $req->set_parameter('omb_listenee_nickname', $user->nickname);
- $req->set_parameter('omb_listenee_license', common_config('license', 'url'));
-
+ /* Create an OMB_Profile from $user. */
$profile = $user->getProfile();
if (!$profile) {
common_log_db_error($user, 'SELECT', __FILE__);
@@ -367,49 +192,16 @@ class RemotesubscribeAction extends Action
return;
}
- if (!is_null($profile->fullname)) {
- $req->set_parameter('omb_listenee_fullname', $profile->fullname);
- }
- if (!is_null($profile->homepage)) {
- $req->set_parameter('omb_listenee_homepage', $profile->homepage);
- }
- if (!is_null($profile->bio)) {
- $req->set_parameter('omb_listenee_bio', $profile->bio);
- }
- if (!is_null($profile->location)) {
- $req->set_parameter('omb_listenee_location', $profile->location);
- }
- $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
- if ($avatar) {
- $req->set_parameter('omb_listenee_avatar', $avatar->url);
- }
-
- # XXX: add a nonce to prevent replay attacks
-
- $req->set_parameter('oauth_callback', common_local_url('finishremotesubscribe'));
-
- # XXX: test to see if endpoint accepts this signature method
-
- $req->sign_request(omb_hmac_sha1(), $con, $tok);
-
- # store all our info here
-
- $omb['listenee'] = $user->nickname;
- $omb['listener'] = omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]);
- $omb['token'] = $token;
- $omb['secret'] = $secret;
- # call doesn't work after bounce back so we cache; maybe serialization issue...?
- $omb['access_token_url'] = omb_service_uri($omb[OAUTH_ENDPOINT_ACCESS]);
- $omb['post_notice_url'] = omb_service_uri($omb[OMB_ENDPOINT_POSTNOTICE]);
- $omb['update_profile_url'] = omb_service_uri($omb[OMB_ENDPOINT_UPDATEPROFILE]);
+ $target_url = $service->requestAuthorization(
+ profile_to_omb_profile($user->uri, $profile),
+ common_local_url('finishremotesubscribe'));
common_ensure_session();
- $_SESSION['oauth_authorization_request'] = $omb;
-
- # Redirect to authorization service
+ $_SESSION['oauth_authorization_request'] = serialize($service);
- common_redirect($req->to_url(), 303);
- return;
+ /* Redirect to the remote service for authorization. */
+ common_redirect($target_url, 303);
}
}
+?>
diff --git a/actions/replies.php b/actions/replies.php
index cca430230..6003ad30b 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/repliesrss.php b/actions/repliesrss.php
index c71c9226f..76aae21ad 100644
--- a/actions/repliesrss.php
+++ b/actions/repliesrss.php
@@ -38,6 +38,7 @@ class RepliesrssAction extends Rss10Action
$this->clientError(_('No such user.'));
return false;
} else {
+ $this->notices = $this->getNotices($this->limit);
return true;
}
}
diff --git a/actions/requesttoken.php b/actions/requesttoken.php
index a17efcdd5..e095161a7 100644
--- a/actions/requesttoken.php
+++ b/actions/requesttoken.php
@@ -34,6 +34,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
}
require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
/**
* Request token action class.
@@ -49,17 +50,17 @@ class RequesttokenAction extends Action
{
/**
* Is read only?
- *
+ *
* @return boolean false
*/
- function isReadOnly($args)
+ function isReadOnly()
{
return false;
}
-
+
/**
* Class handler.
- *
+ *
* @param array $args array of arguments
*
* @return void
@@ -68,14 +69,12 @@ class RequesttokenAction extends Action
{
parent::handle($args);
try {
- common_remove_magic_from_request();
- $req = OAuthRequest::from_request('POST', common_local_url('requesttoken'));
- $server = omb_oauth_server();
- $token = $server->fetch_request_token($req);
- print $token.'&omb_version='.OMB_VERSION_01;
- } catch (OAuthException $e) {
+ $srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
+ omb_oauth_server());
+ $srv->writeRequestToken();
+ } catch (Exception $e) {
$this->serverError($e->getMessage());
}
}
}
-
+?>
diff --git a/actions/showfavorites.php b/actions/showfavorites.php
index 0f7a66330..b96d2af37 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 8157ee3c8..bfe45ddad 100644
--- a/actions/showgroup.php
+++ b/actions/showgroup.php
@@ -101,11 +101,6 @@ class ShowgroupAction extends GroupDesignAction
{
parent::prepare($args);
- if (!common_config('inboxes','enabled')) {
- $this->serverError(_('Inboxes must be enabled for groups to work'));
- return false;
- }
-
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
$nickname_arg = $this->arg('nickname');
@@ -345,7 +340,12 @@ class ShowgroupAction extends GroupDesignAction
'method' => 'timeline',
'argument' => $this->group->nickname.'.atom')),
sprintf(_('Notice feed for %s group (Atom)'),
- $this->group->nickname)));
+ $this->group->nickname)),
+ new Feed(Feed::FOAF,
+ common_local_url('foafgroup',
+ array('nickname' => $this->group->nickname)),
+ sprintf(_('FOAF for %s group'),
+ $this->group->nickname)));
}
/**
@@ -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 [StatusNet](http://status.net/) 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 [StatusNet](http://status.net/) tool. Its members share ' .
diff --git a/actions/shownotice.php b/actions/shownotice.php
index 3bc52b2db..41408c23c 100644
--- a/actions/shownotice.php
+++ b/actions/shownotice.php
@@ -84,7 +84,13 @@ class ShownoticeAction extends OwnerDesignAction
$this->notice = Notice::staticGet($id);
if (empty($this->notice)) {
- $this->clientError(_('No such notice.'), 404);
+ // Did we used to have it, and it got deleted?
+ $deleted = Deleted_notice::staticGet($id);
+ if (!empty($deleted)) {
+ $this->clientError(_('Notice deleted.'), 410);
+ } else {
+ $this->clientError(_('No such notice.'), 404);
+ }
return false;
}
diff --git a/actions/showstream.php b/actions/showstream.php
index 89285b13c..b3a9b1f05 100644
--- a/actions/showstream.php
+++ b/actions/showstream.php
@@ -115,11 +115,11 @@ class ShowstreamAction extends ProfileAction
{
if (!empty($this->tag)) {
return array(new Feed(Feed::RSS1,
- common_local_url('userrss',
- array('nickname' => $this->user->nickname,
- 'tag' => $this->tag)),
- sprintf(_('Notice feed for %s tagged %s (RSS 1.0)'),
- $this->user->nickname, $this->tag)));
+ common_local_url('userrss',
+ array('nickname' => $this->user->nickname,
+ 'tag' => $this->tag)),
+ sprintf(_('Notice feed for %s tagged %s (RSS 1.0)'),
+ $this->user->nickname, $this->tag)));
}
return array(new Feed(Feed::RSS1,
@@ -181,159 +181,251 @@ class ShowstreamAction extends ProfileAction
function showProfile()
{
- $this->elementStart('div', 'entity_profile vcard author');
- $this->element('h2', null, _('User profile'));
-
- $avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
- $this->elementStart('dl', 'entity_depiction');
- $this->element('dt', null, _('Photo'));
- $this->elementStart('dd');
- $this->element('img', array('src' => ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE),
- 'class' => 'photo avatar',
- 'width' => AVATAR_PROFILE_SIZE,
- 'height' => AVATAR_PROFILE_SIZE,
- 'alt' => $this->profile->nickname));
- $this->elementEnd('dd');
-
- $user = User::staticGet('id', $this->profile->id);
- $cur = common_current_user();
- if ($cur && $cur->id == $user->id) {
- $this->elementStart('dd');
- $this->element('a', array('href' => common_local_url('avatarsettings')), _('Edit Avatar'));
- $this->elementEnd('dd');
+ $this->showProfileData();
+ $this->showEntityActions();
+ }
+
+ function showProfileData()
+ {
+ if (Event::handle('StartProfilePageProfileSection', array(&$this, $this->profile))) {
+
+ $this->elementStart('div', 'entity_profile vcard author');
+ $this->element('h2', null, _('User profile'));
+
+ if (Event::handle('StartProfilePageProfileElements', array(&$this, $this->profile))) {
+
+ $this->showAvatar();
+ $this->showNickname();
+ $this->showFullName();
+ $this->showLocation();
+ $this->showHomepage();
+ $this->showBio();
+ $this->showProfileTags();
+
+ Event::handle('EndProfilePageProfileElements', array(&$this, $this->profile));
+ }
+
+ $this->elementEnd('div');
+ Event::handle('EndProfilePageProfileSection', array(&$this, $this->profile));
}
+ }
+
+ function showAvatar()
+ {
+ if (Event::handle('StartProfilePageAvatar', array($this, $this->profile))) {
+
+ $avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
- $this->elementEnd('dl');
-
- $this->elementStart('dl', 'entity_nickname');
- $this->element('dt', null, _('Nickname'));
- $this->elementStart('dd');
- $hasFN = ($this->profile->fullname) ? 'nickname url uid' : 'fn nickname url uid';
- $this->element('a', array('href' => $this->profile->profileurl,
- 'rel' => 'me', 'class' => $hasFN),
- $this->profile->nickname);
- $this->elementEnd('dd');
- $this->elementEnd('dl');
-
- if ($this->profile->fullname) {
- $this->elementStart('dl', 'entity_fn');
- $this->element('dt', null, _('Full name'));
+ $this->elementStart('dl', 'entity_depiction');
+ $this->element('dt', null, _('Photo'));
$this->elementStart('dd');
- $this->element('span', 'fn', $this->profile->fullname);
+ $this->element('img', array('src' => ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_PROFILE_SIZE),
+ 'class' => 'photo avatar',
+ 'width' => AVATAR_PROFILE_SIZE,
+ 'height' => AVATAR_PROFILE_SIZE,
+ 'alt' => $this->profile->nickname));
$this->elementEnd('dd');
- $this->elementEnd('dl');
- }
- if ($this->profile->location) {
- $this->elementStart('dl', 'entity_location');
- $this->element('dt', null, _('Location'));
- $this->element('dd', 'label', $this->profile->location);
+ $user = User::staticGet('id', $this->profile->id);
+
+ $cur = common_current_user();
+ if ($cur && $cur->id == $user->id) {
+ $this->elementStart('dd');
+ $this->element('a', array('href' => common_local_url('avatarsettings')), _('Edit Avatar'));
+ $this->elementEnd('dd');
+ }
+
$this->elementEnd('dl');
+
+ Event::handle('EndProfilePageAvatar', array($this, $this->profile));
}
+ }
+
+ function showNickname()
+ {
+ if (Event::handle('StartProfilePageNickname', array($this, $this->profile))) {
- if ($this->profile->homepage) {
- $this->elementStart('dl', 'entity_url');
- $this->element('dt', null, _('URL'));
+ $this->elementStart('dl', 'entity_nickname');
+ $this->element('dt', null, _('Nickname'));
$this->elementStart('dd');
- $this->element('a', array('href' => $this->profile->homepage,
- 'rel' => 'me', 'class' => 'url'),
- $this->profile->homepage);
+ $hasFN = ($this->profile->fullname) ? 'nickname url uid' : 'fn nickname url uid';
+ $this->element('a', array('href' => $this->profile->profileurl,
+ 'rel' => 'me', 'class' => $hasFN),
+ $this->profile->nickname);
$this->elementEnd('dd');
$this->elementEnd('dl');
+
+ Event::handle('EndProfilePageNickname', array($this, $this->profile));
}
+ }
- if ($this->profile->bio) {
- $this->elementStart('dl', 'entity_note');
- $this->element('dt', null, _('Note'));
- $this->element('dd', 'note', $this->profile->bio);
- $this->elementEnd('dl');
+ function showFullName()
+ {
+ if (Event::handle('StartProfilePageFullName', array($this, $this->profile))) {
+ if ($this->profile->fullname) {
+ $this->elementStart('dl', 'entity_fn');
+ $this->element('dt', null, _('Full name'));
+ $this->elementStart('dd');
+ $this->element('span', 'fn', $this->profile->fullname);
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ }
+ Event::handle('EndProfilePageFullName', array($this, $this->profile));
}
+ }
- $tags = Profile_tag::getTags($this->profile->id, $this->profile->id);
- if (count($tags) > 0) {
- $this->elementStart('dl', 'entity_tags');
- $this->element('dt', null, _('Tags'));
- $this->elementStart('dd');
- $this->elementStart('ul', 'tags xoxo');
- foreach ($tags as $tag) {
- $this->elementStart('li');
- // Avoid space by using raw output.
- $pt = '<span class="mark_hash">#</span><a rel="tag" href="' .
- common_local_url('peopletag', array('tag' => $tag)) .
- '">' . $tag . '</a>';
- $this->raw($pt);
- $this->elementEnd('li');
+ function showLocation()
+ {
+ if (Event::handle('StartProfilePageLocation', array($this, $this->profile))) {
+ if ($this->profile->location) {
+ $this->elementStart('dl', 'entity_location');
+ $this->element('dt', null, _('Location'));
+ $this->element('dd', 'label', $this->profile->location);
+ $this->elementEnd('dl');
}
- $this->elementEnd('ul');
- $this->elementEnd('dd');
- $this->elementEnd('dl');
+ Event::handle('EndProfilePageLocation', array($this, $this->profile));
}
- $this->elementEnd('div');
+ }
- $this->elementStart('div', 'entity_actions');
- $this->element('h2', null, _('User actions'));
- $this->elementStart('ul');
- $cur = common_current_user();
-
- if ($cur && $cur->id == $this->profile->id) {
- $this->elementStart('li', 'entity_edit');
- $this->element('a', array('href' => common_local_url('profilesettings'),
- 'title' => _('Edit profile settings')),
- _('Edit'));
- $this->elementEnd('li');
+ function showHomepage()
+ {
+ if (Event::handle('StartProfilePageHomepage', array($this, $this->profile))) {
+ if ($this->profile->homepage) {
+ $this->elementStart('dl', 'entity_url');
+ $this->element('dt', null, _('URL'));
+ $this->elementStart('dd');
+ $this->element('a', array('href' => $this->profile->homepage,
+ 'rel' => 'me', 'class' => 'url'),
+ $this->profile->homepage);
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
+ }
+ Event::handle('EndProfilePageHomepage', array($this, $this->profile));
}
+ }
- if ($cur) {
- if ($cur->id != $this->profile->id) {
- $this->elementStart('li', 'entity_subscribe');
- if ($cur->isSubscribed($this->profile)) {
- $usf = new UnsubscribeForm($this, $this->profile);
- $usf->show();
- } else {
- $sf = new SubscribeForm($this, $this->profile);
- $sf->show();
- }
- $this->elementEnd('li');
+ function showBio()
+ {
+ if (Event::handle('StartProfilePageBio', array($this, $this->profile))) {
+ if ($this->profile->bio) {
+ $this->elementStart('dl', 'entity_note');
+ $this->element('dt', null, _('Note'));
+ $this->element('dd', 'note', $this->profile->bio);
+ $this->elementEnd('dl');
}
- } else {
- $this->elementStart('li', 'entity_subscribe');
- $this->showRemoteSubscribeLink();
- $this->elementEnd('li');
+ Event::handle('EndProfilePageBio', array($this, $this->profile));
}
+ }
- if ($cur && $cur->id != $user->id && $cur->mutuallySubscribed($user)) {
- $this->elementStart('li', 'entity_send-a-message');
- $this->element('a', array('href' => common_local_url('newmessage', array('to' => $user->id)),
- 'title' => _('Send a direct message to this user')),
- _('Message'));
- $this->elementEnd('li');
-
- if ($user->email && $user->emailnotifynudge) {
- $this->elementStart('li', 'entity_nudge');
- $nf = new NudgeForm($this, $user);
- $nf->show();
- $this->elementEnd('li');
+ function showProfileTags()
+ {
+ if (Event::handle('StartProfilePageProfileTags', array($this, $this->profile))) {
+ $tags = Profile_tag::getTags($this->profile->id, $this->profile->id);
+
+ if (count($tags) > 0) {
+ $this->elementStart('dl', 'entity_tags');
+ $this->element('dt', null, _('Tags'));
+ $this->elementStart('dd');
+ $this->elementStart('ul', 'tags xoxo');
+ foreach ($tags as $tag) {
+ $this->elementStart('li');
+ // Avoid space by using raw output.
+ $pt = '<span class="mark_hash">#</span><a rel="tag" href="' .
+ common_local_url('peopletag', array('tag' => $tag)) .
+ '">' . $tag . '</a>';
+ $this->raw($pt);
+ $this->elementEnd('li');
+ }
+ $this->elementEnd('ul');
+ $this->elementEnd('dd');
+ $this->elementEnd('dl');
}
+ Event::handle('EndProfilePageProfileTags', array($this, $this->profile));
}
+ }
- if ($cur && $cur->id != $this->profile->id) {
- $blocked = $cur->hasBlocked($this->profile);
- $this->elementStart('li', 'entity_block');
- if ($blocked) {
- $ubf = new UnblockForm($this, $this->profile,
- array('action' => 'showstream',
- 'nickname' => $this->profile->nickname));
- $ubf->show();
- } else {
- $bf = new BlockForm($this, $this->profile,
- array('action' => 'showstream',
- 'nickname' => $this->profile->nickname));
- $bf->show();
+ function showEntityActions()
+ {
+ if (Event::handle('StartProfilePageActionsSection', array(&$this, $this->profile))) {
+
+ $this->elementStart('div', 'entity_actions');
+ $this->element('h2', null, _('User actions'));
+ $this->elementStart('ul');
+
+ if (Event::handle('StartProfilePageActionsElements', array(&$this, $this->profile))) {
+ if (empty($cur)) { // not logged in
+ $this->elementStart('li', 'entity_subscribe');
+ $this->showRemoteSubscribeLink();
+ $this->elementEnd('li');
+ } else {
+ if ($cur->id == $this->profile->id) { // your own page
+ $this->elementStart('li', 'entity_edit');
+ $this->element('a', array('href' => common_local_url('profilesettings'),
+ 'title' => _('Edit profile settings')),
+ _('Edit'));
+ $this->elementEnd('li');
+ } else { // someone else's page
+
+ // subscribe/unsubscribe button
+
+ $this->elementStart('li', 'entity_subscribe');
+
+ if ($cur->isSubscribed($this->profile)) {
+ $usf = new UnsubscribeForm($this, $this->profile);
+ $usf->show();
+ } else {
+ $sf = new SubscribeForm($this, $this->profile);
+ $sf->show();
+ }
+ $this->elementEnd('li');
+
+ if ($cur->mutuallySubscribed($user)) {
+
+ // message
+
+ $this->elementStart('li', 'entity_send-a-message');
+ $this->element('a', array('href' => common_local_url('newmessage', array('to' => $user->id)),
+ 'title' => _('Send a direct message to this user')),
+ _('Message'));
+ $this->elementEnd('li');
+
+ // nudge
+
+ if ($user->email && $user->emailnotifynudge) {
+ $this->elementStart('li', 'entity_nudge');
+ $nf = new NudgeForm($this, $user);
+ $nf->show();
+ $this->elementEnd('li');
+ }
+ }
+
+ // block/unblock
+
+ $blocked = $cur->hasBlocked($this->profile);
+ $this->elementStart('li', 'entity_block');
+ if ($blocked) {
+ $ubf = new UnblockForm($this, $this->profile,
+ array('action' => 'showstream',
+ 'nickname' => $this->profile->nickname));
+ $ubf->show();
+ } else {
+ $bf = new BlockForm($this, $this->profile,
+ array('action' => 'showstream',
+ 'nickname' => $this->profile->nickname));
+ $bf->show();
+ }
+ $this->elementEnd('li');
+ }
+ }
+
+ Event::handle('EndProfilePageActionsElements', array(&$this, $this->profile));
}
- $this->elementEnd('li');
+
+ $this->elementEnd('ul');
+ $this->elementEnd('div');
+
+ Event::handle('EndProfilePageActionsSection', array(&$this, $this->profile));
}
- $this->elementEnd('ul');
- $this->elementEnd('div');
}
function showRemoteSubscribeLink()
@@ -358,9 +450,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');
@@ -371,7 +461,7 @@ class ShowstreamAction extends ProfileAction
function showNotices()
{
$notice = empty($this->tag)
- ? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
+ ? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
: $this->user->getTaggedNotices($this->tag, ($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null);
$pnl = new ProfileNoticeList($notice, $this);
@@ -393,16 +483,14 @@ 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 [StatusNet](http://status.net/) 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);
+ 'based on the Free Software [StatusNet](http://status.net/) tool. ' .
+ '[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 [StatusNet](http://status.net/) tool. '),
- $this->user->nickname, $this->user->nickname);
- }
+ 'based on the Free Software [StatusNet](http://status.net/) tool. '),
+ $this->user->nickname, $this->user->nickname);
+ }
$this->elementStart('div', array('id' => 'anon_notice'));
$this->raw(common_markup_to_html($m));
$this->elementEnd('div');
diff --git a/actions/subscribers.php b/actions/subscribers.php
index f7d08d9d0..df9ec9961 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/twitapiaccount.php b/actions/twitapiaccount.php
deleted file mode 100644
index 93c8443c9..000000000
--- a/actions/twitapiaccount.php
+++ /dev/null
@@ -1,127 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class TwitapiaccountAction extends TwitterapiAction
-{
- function verify_credentials($args, $apidata)
- {
- parent::handle($args);
-
- switch ($apidata['content-type']) {
- case 'xml':
- case 'json':
- $action_obj = new TwitapiusersAction();
- $action_obj->prepare($args);
- call_user_func(array($action_obj, 'show'), $args, $apidata);
- break;
- default:
- header('Content-Type: text/html; charset=utf-8');
- print 'Authorized';
- }
- }
-
- function end_session($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
- }
-
- function update_location($args, $apidata)
- {
- parent::handle($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(_('This method requires a POST.'),
- 400, $apidata['content-type']);
- return;
- }
-
- $location = trim($this->arg('location'));
-
- if (!is_null($location) && mb_strlen($location) > 255) {
-
- // XXX: But Twitter just truncates and runs with it. -- Zach
- $this->clientError(_('That\'s too long. Max notice size is 255 chars.'),
- 406, $apidate['content-type']);
- return;
- }
-
- $user = $apidata['user']; // Always the auth user
- $profile = $user->getProfile();
-
- $orig_profile = clone($profile);
- $profile->location = $location;
-
- $result = $profile->update($orig_profile);
-
- if (empty($result)) {
- common_log_db_error($profile, 'UPDATE', __FILE__);
- $this->serverError(_('Couldn\'t save profile.'));
- return;
- }
-
- common_broadcast_profile($profile);
- $type = $apidata['content-type'];
-
- $this->init_document($type);
- $this->show_profile($profile, $type);
- $this->end_document($type);
- }
-
-
- function update_delivery_device($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
- }
-
- // We don't have a rate limit, but some clients check this method.
- // It always returns the same thing: 100 hit left.
- function rate_limit_status($args, $apidata)
- {
- parent::handle($args);
-
- $type = $apidata['content-type'];
- $this->init_document($type);
-
- if ($apidata['content-type'] == 'xml') {
- $this->elementStart('hash');
- $this->element('remaining-hits', array('type' => 'integer'), 100);
- $this->element('hourly-limit', array('type' => 'integer'), 100);
- $this->element('reset-time', array('type' => 'datetime'), null);
- $this->element('reset_time_in_seconds', array('type' => 'integer'), 0);
- $this->elementEnd('hash');
- } elseif ($apidata['content-type'] == 'json') {
-
- $out = array('reset_time_in_seconds' => 0,
- 'remaining_hits' => 100,
- 'hourly_limit' => 100,
- 'reset_time' => '');
- print json_encode($out);
- }
-
- $this->end_document($type);
- }
-}
diff --git a/actions/twitapiblocks.php b/actions/twitapiblocks.php
deleted file mode 100644
index ed17946ae..000000000
--- a/actions/twitapiblocks.php
+++ /dev/null
@@ -1,74 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class TwitapiblocksAction extends TwitterapiAction
-{
-
- function create($args, $apidata)
- {
-
- parent::handle($args);
-
- $blockee = $this->get_user($apidata['api_arg'], $apidata);
-
- if (empty($blockee)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $user = $apidata['user']; // Always the auth user
-
- if ($user->hasBlocked($blockee) || $user->block($blockee)) {
- $type = $apidata['content-type'];
- $this->init_document($type);
- $this->show_profile($blockee, $type);
- $this->end_document($type);
- } else {
- $this->serverError(_('Block user failed.'));
- }
- }
-
- function destroy($args, $apidata)
- {
- parent::handle($args);
- $blockee = $this->get_user($apidata['api_arg'], $apidata);
-
- if (empty($blockee)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $user = $apidata['user'];
-
- if (!$user->hasBlocked($blockee) || $user->unblock($blockee)) {
- $type = $apidata['content-type'];
- $this->init_document($type);
- $this->show_profile($blockee, $type);
- $this->end_document($type);
- } else {
- $this->serverError(_('Unblock user failed.'));
- }
- }
-} \ No newline at end of file
diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php
deleted file mode 100644
index dbe55804b..000000000
--- a/actions/twitapidirect_messages.php
+++ /dev/null
@@ -1,304 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class Twitapidirect_messagesAction extends TwitterapiAction
-{
-
- function direct_messages($args, $apidata)
- {
- parent::handle($args);
- return $this->show_messages($args, $apidata, 'received');
- }
-
- function sent($args, $apidata)
- {
- parent::handle($args);
- return $this->show_messages($args, $apidata, 'sent');
- }
-
- function show_messages($args, $apidata, $type)
- {
- $user = $apidata['user']; // Always the auth user
-
- $message = new Message();
- $title = null;
- $subtitle = null;
- $link = null;
- $server = common_root_url();
-
- if ($type == 'received') {
- $message->to_profile = $user->id;
- $title = sprintf(_("Direct messages to %s"), $user->nickname);
- $subtitle = sprintf(_("All the direct messages sent to %s"),
- $user->nickname);
- $link = $server . $user->nickname . '/inbox';
- } else {
- $message->from_profile = $user->id;
- $title = _('Direct Messages You\'ve Sent');
- $subtitle = sprintf(_("All the direct messages sent from %s"),
- $user->nickname);
- $link = $server . $user->nickname . '/outbox';
- }
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- if ($max_id) {
- $message->whereAdd("id <= $max_id");
- }
-
- if ($since_id) {
- $message->whereAdd("id > $since_id");
- }
-
- if ($since) {
- $d = date('Y-m-d H:i:s', $since);
- $message->whereAdd("created > '$d'");
- }
-
- $message->orderBy('created DESC, id DESC');
- $message->limit((($page-1)*$count), $count);
- $message->find();
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_dmsgs($message);
- break;
- case 'rss':
- $this->show_rss_dmsgs($message, $title, $link, $subtitle);
- break;
- case 'atom':
- $selfuri = common_root_url() . 'api/direct_messages';
- $selfuri .= ($type == 'received') ? '.atom' : '/sent.atom';
- $taguribase = common_config('integration', 'taguri');
-
- if ($type == 'sent') {
- $id = "tag:$taguribase:SentDirectMessages:" . $user->id;
- } else {
- $id = "tag:$taguribase:DirectMessages:" . $user->id;
- }
-
- $this->show_atom_dmsgs($message, $title, $link, $subtitle,
- $selfuri, $id);
- break;
- case 'json':
- $this->show_json_dmsgs($message);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
-
- }
-
- // had to change this from "new" to "create" to avoid PHP reserved word
- function create($args, $apidata)
- {
- parent::handle($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(_('This method requires a POST.'),
- 400, $apidata['content-type']);
- return;
- }
-
- $user = $apidata['user'];
- $source = $this->trimmed('source'); // Not supported by Twitter.
-
- $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
- if (empty($source) || in_array($source, $reserved_sources)) {
- $source = 'api';
- }
-
- $content = $this->trimmed('text');
-
- if (empty($content)) {
- $this->clientError(_('No message text!'),
- $code = 406, $apidata['content-type']);
- } else {
- $content_shortened = common_shorten_links($content);
- if (mb_strlen($content_shortened) > 140) {
- $this->clientError(_('That\'s too long. Max message size is 140 chars.'),
- $code = 406, $apidata['content-type']);
- return;
- }
- }
-
- $other = $this->get_user($this->trimmed('user'));
-
- if (empty($other)) {
- $this->clientError(_('Recipient user not found.'),
- $code = 403, $apidata['content-type']);
- return;
- } else if (!$user->mutuallySubscribed($other)) {
- $this->clientError(_('Can\'t send direct messages to users who aren\'t your friend.'),
- $code = 403, $apidata['content-type']);
- return;
- } else if ($user->id == $other->id) {
- // Sending msgs to yourself is allowed by Twitter
- $this->clientError(_('Don\'t send a message to yourself; just say it to yourself quietly instead.'),
- $code = 403, $apidata['content-type']);
- return;
- }
-
- $message = Message::saveNew($user->id, $other->id,
- html_entity_decode($content, ENT_NOQUOTES, 'UTF-8'), $source);
-
- if (is_string($message)) {
- $this->serverError($message);
- return;
- }
-
- $this->notify($user, $other, $message);
-
- if ($apidata['content-type'] == 'xml') {
- $this->show_single_xml_dmsg($message);
- } elseif ($apidata['content-type'] == 'json') {
- $this->show_single_json_dmsg($message);
- }
-
- }
-
- function destroy($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
- }
-
- function show_xml_dmsgs($message)
- {
-
- $this->init_document('xml');
- $this->elementStart('direct-messages', array('type' => 'array'));
-
- if (is_array($message)) {
- foreach ($message as $m) {
- $twitter_dm = $this->twitter_dmsg_array($m);
- $this->show_twitter_xml_dmsg($twitter_dm);
- }
- } else {
- while ($message->fetch()) {
- $twitter_dm = $this->twitter_dmsg_array($message);
- $this->show_twitter_xml_dmsg($twitter_dm);
- }
- }
-
- $this->elementEnd('direct-messages');
- $this->end_document('xml');
-
- }
-
- function show_json_dmsgs($message)
- {
-
- $this->init_document('json');
-
- $dmsgs = array();
-
- if (is_array($message)) {
- foreach ($message as $m) {
- $twitter_dm = $this->twitter_dmsg_array($m);
- array_push($dmsgs, $twitter_dm);
- }
- } else {
- while ($message->fetch()) {
- $twitter_dm = $this->twitter_dmsg_array($message);
- array_push($dmsgs, $twitter_dm);
- }
- }
-
- $this->show_json_objects($dmsgs);
- $this->end_document('json');
-
- }
-
- function show_rss_dmsgs($message, $title, $link, $subtitle)
- {
-
- $this->init_document('rss');
-
- $this->elementStart('channel');
- $this->element('title', null, $title);
-
- $this->element('link', null, $link);
- $this->element('description', null, $subtitle);
- $this->element('language', null, 'en-us');
- $this->element('ttl', null, '40');
-
- if (is_array($message)) {
- foreach ($message as $m) {
- $entry = $this->twitter_rss_dmsg_array($m);
- $this->show_twitter_rss_item($entry);
- }
- } else {
- while ($message->fetch()) {
- $entry = $this->twitter_rss_dmsg_array($message);
- $this->show_twitter_rss_item($entry);
- }
- }
-
- $this->elementEnd('channel');
- $this->end_twitter_rss();
-
- }
-
- function show_atom_dmsgs($message, $title, $link, $subtitle, $selfuri, $id)
- {
-
- $this->init_document('atom');
-
- $this->element('title', null, $title);
- $this->element('id', null, $id);
- $this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null);
- $this->element('link', array('href' => $selfuri, 'rel' => 'self',
- 'type' => 'application/atom+xml'), null);
- $this->element('updated', null, common_date_iso8601('now'));
- $this->element('subtitle', null, $subtitle);
-
- if (is_array($message)) {
- foreach ($message as $m) {
- $entry = $this->twitter_rss_dmsg_array($m);
- $this->show_twitter_atom_entry($entry);
- }
- } else {
- while ($message->fetch()) {
- $entry = $this->twitter_rss_dmsg_array($message);
- $this->show_twitter_atom_entry($entry);
- }
- }
-
- $this->end_document('atom');
- }
-
- // swiped from MessageAction. Should it be place in util.php?
- function notify($from, $to, $message)
- {
- mail_notify_message($message, $from, $to);
- # XXX: Jabber, SMS notifications... probably queued
- }
-
-}
diff --git a/actions/twitapifavorites.php b/actions/twitapifavorites.php
deleted file mode 100644
index f8943fe2d..000000000
--- a/actions/twitapifavorites.php
+++ /dev/null
@@ -1,216 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class TwitapifavoritesAction extends TwitterapiAction
-{
-
- function favorites($args, $apidata)
- {
- parent::handle($args);
-
- $this->auth_user = $apidata['user'];
- $user = $this->get_user($apidata['api_arg'], $apidata);
-
- if (empty($user)) {
- if ($apidata['content-type'] == 'xml') {
- $this->show_single_xml_status($notice);
- } elseif ($apidata['content-type'] == 'json') {
- $this->show_single_json_status($notice);
- }
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $profile = $user->getProfile();
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_('%s / Favorites from %s'), $sitename,
- $user->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:Favorites:".$user->id;
- $link = common_local_url('favorites',
- array('nickname' => $user->nickname));
- $subtitle = sprintf(_('%s updates favorited by %s / %s.'), $sitename,
- $profile->getBestName(), $user->nickname);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- if (!empty($this->auth_user) && $this->auth_user->id == $user->id) {
- $notice = $user->favoriteNotices(($page-1)*$count, $count, true);
- } else {
- $notice = $user->favoriteNotices(($page-1)*$count, $count, false);
- }
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link, $subtitle);
- break;
- case 'atom':
- if (isset($apidata['api_arg'])) {
- $selfuri = $selfuri = common_root_url() .
- 'api/favorites/' . $apidata['api_arg'] . '.atom';
- } else {
- $selfuri = $selfuri = common_root_url() .
- 'api/favorites.atom';
- }
- $this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, null, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
-
- }
-
- function create($args, $apidata)
- {
- parent::handle($args);
-
- // Check for RESTfulness
- if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
- $this->clientError(_('This method requires a POST or DELETE.'),
- 400, $apidata['content-type']);
- return;
- }
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- $user = $apidata['user']; // Always the auth user
- $notice_id = $apidata['api_arg'];
- $notice = Notice::staticGet($notice_id);
-
- if (empty($notice)) {
- $this->clientError(_('No status found with that ID.'),
- 404, $apidata['content-type']);
- return;
- }
-
- // XXX: Twitter lets you fave things repeatedly via api.
- if ($user->hasFave($notice)) {
- $this->clientError(_('This status is already a favorite!'),
- 403, $apidata['content-type']);
- return;
- }
-
- $fave = Fave::addNew($user, $notice);
-
- if (empty($fave)) {
- $this->clientError(_('Could not create favorite.'));
- return;
- }
-
- $this->notify($fave, $notice, $user);
- $user->blowFavesCache();
-
- if ($apidata['content-type'] == 'xml') {
- $this->show_single_xml_status($notice);
- } elseif ($apidata['content-type'] == 'json') {
- $this->show_single_json_status($notice);
- }
-
- }
-
- function destroy($args, $apidata)
- {
- parent::handle($args);
-
- // Check for RESTfulness
- if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
- $this->clientError(_('This method requires a POST or DELETE.'),
- 400, $apidata['content-type']);
- return;
- }
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- $user = $apidata['user']; // Always the auth user
- $notice_id = $apidata['api_arg'];
- $notice = Notice::staticGet($notice_id);
-
- if (empty($notice)) {
- $this->clientError(_('No status found with that ID.'),
- 404, $apidata['content-type']);
- return;
- }
-
- $fave = new Fave();
- $fave->user_id = $this->id;
- $fave->notice_id = $notice->id;
-
- if (!$fave->find(true)) {
- $this->clientError(_('That status is not a favorite!'),
- 403, $apidata['content-type']);
- return;
- }
-
- $result = $fave->delete();
-
- if (!$result) {
- common_log_db_error($fave, 'DELETE', __FILE__);
- $this->clientError(_('Could not delete favorite.'), 404);
- return;
- }
-
- $user->blowFavesCache();
-
- if ($apidata['content-type'] == 'xml') {
- $this->show_single_xml_status($notice);
- } elseif ($apidata['content-type'] == 'json') {
- $this->show_single_json_status($notice);
- }
-
- }
-
- // XXX: these two funcs swiped from faves.
- // Maybe put in util.php, or some common base class?
-
- function notify($fave, $notice, $user)
- {
- $other = User::staticGet('id', $notice->profile_id);
- if ($other && $other->id != $user->id) {
- if ($other->email && $other->emailnotifyfav) {
- mail_notify_fave($other, $user, $notice);
- }
- # XXX: notify by IM
- # XXX: notify by SMS
- }
- }
-}
diff --git a/actions/twitapifriendships.php b/actions/twitapifriendships.php
deleted file mode 100644
index eea8945c3..000000000
--- a/actions/twitapifriendships.php
+++ /dev/null
@@ -1,250 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class TwitapifriendshipsAction extends TwitterapiAction
-{
-
- function create($args, $apidata)
- {
- parent::handle($args);
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(_('This method requires a POST.'),
- 400, $apidata['content-type']);
- return;
- }
-
- $id = $apidata['api_arg'];
- $other = $this->get_user($id);
-
- if (empty($other)) {
- $this->clientError(_('Could not follow user: User not found.'),
- 403, $apidata['content-type']);
- return;
- }
-
- $user = $apidata['user'];
-
- if ($user->isSubscribed($other)) {
- $errmsg = sprintf(_('Could not follow user: %s is already on your list.'),
- $other->nickname);
- $this->clientError($errmsg, 403, $apidata['content-type']);
- return;
- }
-
- $sub = new Subscription();
-
- $sub->query('BEGIN');
-
- $sub->subscriber = $user->id;
- $sub->subscribed = $other->id;
- $sub->created = DB_DataObject_Cast::dateTime(); # current time
-
- $result = $sub->insert();
-
- if (empty($result)) {
- $errmsg = sprintf(_('Could not follow user: %s is already on your list.'),
- $other->nickname);
- $this->clientError($errmsg, 400, $apidata['content-type']);
- return;
- }
-
- $sub->query('COMMIT');
-
- mail_subscribe_notify($other, $user);
-
- $type = $apidata['content-type'];
- $this->init_document($type);
- $this->show_profile($other, $type);
- $this->end_document($type);
-
- }
-
- function destroy($args, $apidata)
- {
- parent::handle($args);
-
- if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
- $this->clientError(_('This method requires a POST or DELETE.'),
- 400, $apidata['content-type']);
- return;
- }
-
- $id = $apidata['api_arg'];
-
- # We can't subscribe to a remote person, but we can unsub
-
- $other = $this->get_profile($id);
- $user = $apidata['user']; // Alwyas the auth user
-
- if ($user->id == $other->id) {
- $this->clientError(_("You cannot unfollow yourself!"),
- 403, $apidata['content-type']);
- return;
- }
-
- $sub = new Subscription();
- $sub->subscriber = $user->id;
- $sub->subscribed = $other->id;
-
- if ($sub->find(true)) {
- $sub->query('BEGIN');
- $sub->delete();
- $sub->query('COMMIT');
- } else {
- $this->clientError(_('You are not friends with the specified user.'),
- 403, $apidata['content-type']);
- return;
- }
-
- $type = $apidata['content-type'];
- $this->init_document($type);
- $this->show_profile($other, $type);
- $this->end_document($type);
-
- }
-
- function exists($args, $apidata)
- {
- parent::handle($args);
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- $user_a_id = $this->trimmed('user_a');
- $user_b_id = $this->trimmed('user_b');
-
- $user_a = $this->get_user($user_a_id);
- $user_b = $this->get_user($user_b_id);
-
- if (empty($user_a) || empty($user_b)) {
- $this->clientError(_('Two user ids or screen_names must be supplied.'),
- 400, $apidata['content-type']);
- return;
- }
-
- $result = $user_a->isSubscribed($user_b);
-
- switch ($apidata['content-type']) {
- case 'xml':
- $this->init_document('xml');
- $this->element('friends', null, $result);
- $this->end_document('xml');
- break;
- case 'json':
- $this->init_document('json');
- print json_encode($result);
- $this->end_document('json');
- break;
- default:
- break;
- }
-
- }
-
- function show($args, $apidata)
- {
- parent::handle($args);
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- $source_id = (int)$this->trimmed('source_id');
- $source_screen_name = $this->trimmed('source_screen_name');
-
- // If the source is not specified for an unauthenticated request,
- // the method will return an HTTP 403.
-
- if (empty($source_id) && empty($source_screen_name)) {
- if (empty($apidata['user'])) {
- $this->clientError(_('Could not determine source user.'),
- $code = 403);
- return;
- }
- }
-
- $source = null;
-
- if (!empty($source_id)) {
- $source = User::staticGet($source_id);
- } elseif (!empty($source_screen_name)) {
- $source = User::staticGet('nickname', $source_screen_name);
- } else {
- $source = $apidata['user'];
- }
-
- // If a source or target is specified but does not exist,
- // the method will return an HTTP 404.
-
- if (empty($source)) {
- $this->clientError(_('Could not determine source user.'),
- $code = 404);
- return;
- }
-
- $target_id = (int)$this->trimmed('target_id');
- $target_screen_name = $this->trimmed('target_screen_name');
-
- $target = null;
-
- if (!empty($target_id)) {
- $target = User::staticGet($target_id);
- } elseif (!empty($target_screen_name)) {
- $target = User::staticGet('nickname', $target_screen_name);
- } else {
- $this->clientError(_('Target user not specified.'),
- $code = 403);
- return;
- }
-
- if (empty($target)) {
- $this->clientError(_('Could not find target user.'),
- $code = 404);
- return;
- }
-
- $result = $this->twitter_relationship_array($source, $target);
-
- switch ($apidata['content-type']) {
- case 'xml':
- $this->init_document('xml');
- $this->show_twitter_xml_relationship($result[relationship]);
- $this->end_document('xml');
- break;
- case 'json':
- $this->init_document('json');
- print json_encode($result);
- $this->end_document('json');
- break;
- default:
- break;
- }
- }
-
-}
diff --git a/actions/twitapigroups.php b/actions/twitapigroups.php
deleted file mode 100644
index 4deb1b764..000000000
--- a/actions/twitapigroups.php
+++ /dev/null
@@ -1,329 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * StatusNet extensions to the Twitter-like API for groups
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category Twitter
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Zach Copley <zach@status.net>
- * @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') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/twitterapi.php';
-
-/**
- * Group-specific API methods
- *
- * This class handles StatusNet group API methods.
- *
- * @category Twitter
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Zach Copley <zach@status.net>
- * @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/
- */
-
- class TwitapigroupsAction extends TwitterapiAction
- {
-
- function list_groups($args, $apidata)
- {
- parent::handle($args);
-
- common_debug("in groups api action");
-
- $this->auth_user = $apidata['user'];
- $user = $this->get_user($apidata['api_arg'], $apidata);
-
- if (empty($user)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
- $group = $user->getGroups(($page-1)*$count,
- $count, $since_id, $max_id, $since);
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("%s's groups"), $user->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:Groups";
- $link = common_root_url();
- $subtitle = sprintf(_("groups %s is a member of on %s"), $user->nickname, $sitename);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_groups($group);
- break;
- case 'rss':
- $this->show_rss_groups($group, $title, $link, $subtitle);
- break;
- case 'atom':
- $selfuri = common_root_url() . 'api/statusnet/groups/list/' . $user->id . '.atom';
- $this->show_atom_groups($group, $title, $id, $link,
- $subtitle, $selfuri);
- break;
- case 'json':
- $this->show_json_groups($group);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- break;
- }
- }
-
- function list_all($args, $apidata)
- {
- parent::handle($args);
-
- common_debug("in groups api action");
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- /* TODO:
- Use the $page, $count, $max_id, $since_id, and $since parameters
- */
- $group = new User_group();
- $group->orderBy('created DESC');
- $group->find();
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("%s groups"), $sitename);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:Groups";
- $link = common_root_url();
- $subtitle = sprintf(_("groups on %s"), $sitename);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_groups($group);
- break;
- case 'rss':
- $this->show_rss_groups($group, $title, $link, $subtitle);
- break;
- case 'atom':
- $selfuri = common_root_url() . 'api/statusnet/groups/list_all.atom';
- $this->show_atom_groups($group, $title, $id, $link,
- $subtitle, $selfuri);
- break;
- case 'json':
- $this->show_json_groups($group);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- break;
- }
- }
-
- function show($args, $apidata)
- {
- parent::handle($args);
-
- common_debug("in groups api action");
-
- $this->auth_user = $apidata['user'];
- $group = $this->get_group($apidata['api_arg'], $apidata);
-
- if (empty($group)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_single_xml_group($group);
- break;
- case 'json':
- $this->show_single_json_group($group);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
- }
-
- function timeline($args, $apidata)
- {
- parent::handle($args);
-
- common_debug("in groups api action");
-
- $this->auth_user = $apidata['user'];
- $group = $this->get_group($apidata['api_arg'], $apidata);
-
- if (empty($group)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("%s timeline"), $group->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:GroupTimeline:".$group->id;
- $link = common_local_url('showgroup',
- array('nickname' => $group->nickname));
- $subtitle = sprintf(_('Updates from %1$s on %2$s!'),
- $group->nickname, $sitename);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- $notice = $group->getNotices(($page-1)*$count,
- $count, $since_id, $max_id, $since);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link, $subtitle);
- break;
- case 'atom':
- if (isset($apidata['api_arg'])) {
- $selfuri = common_root_url() .
- 'api/statusnet/groups/timeline/' .
- $apidata['api_arg'] . '.atom';
- } else {
- $selfuri = common_root_url() .
- 'api/statusnet/groups/timeline.atom';
- }
- $this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, null, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
- }
-
- function membership($args, $apidata)
- {
- parent::handle($args);
-
- common_debug("in groups api action");
-
- $this->auth_user = $apidata['user'];
- $group = $this->get_group($apidata['api_arg'], $apidata);
-
- if (empty($group)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("Members of %s group"), $group->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:GroupMembership:".$group->id;
- $link = common_local_url('showgroup',
- array('nickname' => $group->nickname));
- $subtitle = sprintf(_('Members of %1$s on %2$s'),
- $group->nickname, $sitename);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- $member = $group->getMembers(($page-1)*$count,
- $count, $since_id, $max_id, $since);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_twitter_xml_users($member);
- break;
- //TODO implement the RSS and ATOM content types
- /*case 'rss':
- $this->show_rss_users($member, $title, $link, $subtitle);
- break;*/
- /*case 'atom':
- if (isset($apidata['api_arg'])) {
- $selfuri = common_root_url() .
- 'api/statusnet/groups/membership/' .
- $apidata['api_arg'] . '.atom';
- } else {
- $selfuri = common_root_url() .
- 'api/statusnet/groups/membership.atom';
- }
- $this->show_atom_users($member, $title, $id, $link,
- $subtitle, null, $selfuri);
- break;*/
- case 'json':
- $this->show_json_users($member);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
- }
-
- function is_member($args, $apidata)
- {
- parent::handle($args);
-
- common_debug("in groups api action");
-
- $this->auth_user = $apidata['user'];
- $group = User_group::staticGet($args['group_id']);
- if(! $group){
- $this->clientError(_('Group not found'), $code = 500);
- }
- $user = User::staticGet('id', $args['user_id']);
- if(! $user){
- $this->clientError(_('User not found'), $code = 500);
- }
-
- $is_member=$user->isMember($group);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->init_document('xml');
- $this->element('is_member', null, $is_member);
- $this->end_document('xml');
- break;
- case 'json':
- $this->init_document('json');
- $this->show_json_objects(array('is_member'=>$is_member));
- $this->end_document('json');
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
- }
-}
diff --git a/actions/twitapihelp.php b/actions/twitapihelp.php
deleted file mode 100644
index 81381620e..000000000
--- a/actions/twitapihelp.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class TwitapihelpAction extends TwitterapiAction
-{
-
- /* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
- * URL:http://identi.ca/api/help/test.format
- * Formats: xml, json
- */
- function test($args, $apidata)
- {
- parent::handle($args);
-
- if ($apidata['content-type'] == 'xml') {
- $this->init_document('xml');
- $this->element('ok', null, 'true');
- $this->end_document('xml');
- } elseif ($apidata['content-type'] == 'json') {
- $this->init_document('json');
- print '"ok"';
- $this->end_document('json');
- } else {
- $this->clientError(_('API method not found!'), $code=404);
- }
-
- }
-
- function downtime_schedule($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
- }
-
-} \ No newline at end of file
diff --git a/actions/twitapinotifications.php b/actions/twitapinotifications.php
deleted file mode 100644
index 0653e69ab..000000000
--- a/actions/twitapinotifications.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-# This naming convention looks real sick
-class TwitapinotificationsAction extends TwitterapiAction
-{
-
- function follow($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
- }
-
- function leave($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
- }
-
-} \ No newline at end of file
diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php
index 2f587d604..7d618c471 100644
--- a/actions/twitapisearchatom.php
+++ b/actions/twitapisearchatom.php
@@ -31,7 +31,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once INSTALLDIR.'/lib/twitterapi.php';
+require_once INSTALLDIR.'/lib/api.php';
/**
* Action for outputting search results in Twitter compatible Atom
@@ -46,10 +46,10 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
- * @see TwitterapiAction
+ * @see ApiAction
*/
-class TwitapisearchatomAction extends TwitterapiAction
+class TwitapisearchatomAction extends ApiAction
{
var $cnt;
@@ -340,7 +340,7 @@ class TwitapisearchatomAction extends TwitterapiAction
// TODO: Here is where we'd put in a link to an atom feed for threads
$this->element("twitter:source", null,
- htmlentities($this->source_link($notice->source)));
+ htmlentities($this->sourceLink($notice->source)));
$this->elementStart('author');
diff --git a/actions/twitapisearchjson.php b/actions/twitapisearchjson.php
index c628ee624..c7fa741a0 100644
--- a/actions/twitapisearchjson.php
+++ b/actions/twitapisearchjson.php
@@ -31,7 +31,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once INSTALLDIR.'/lib/twitterapi.php';
+require_once INSTALLDIR.'/lib/api.php';
require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
/**
@@ -42,10 +42,10 @@ require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
- * @see TwitterapiAction
+ * @see ApiAction
*/
-class TwitapisearchjsonAction extends TwitterapiAction
+class TwitapisearchjsonAction extends ApiAction
{
var $query;
var $lang;
@@ -134,9 +134,9 @@ class TwitapisearchjsonAction extends TwitterapiAction
$results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page);
- $this->init_document('json');
+ $this->initDocument('json');
$results->show();
- $this->end_document('json');
+ $this->endDocument('json');
}
/**
diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php
deleted file mode 100644
index 360dff27c..000000000
--- a/actions/twitapistatuses.php
+++ /dev/null
@@ -1,604 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class TwitapistatusesAction extends TwitterapiAction
-{
-
- function public_timeline($args, $apidata)
- {
- // XXX: To really live up to the spec we need to build a list
- // of notices by users who have custom avatars, so fix this SQL -- Zach
-
- parent::handle($args);
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("%s public timeline"), $sitename);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:PublicTimeline";
- $link = common_root_url();
- $subtitle = sprintf(_("%s updates from everyone!"), $sitename);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- $notice = Notice::publicStream(($page-1)*$count, $count, $since_id,
- $max_id, $since);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link, $subtitle);
- break;
- case 'atom':
- $selfuri = common_root_url() . 'api/statuses/public_timeline.atom';
- $this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, null, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- break;
- }
-
- }
-
- function friends_timeline($args, $apidata)
- {
- parent::handle($args);
-
- $this->auth_user = $apidata['user'];
- $user = $this->get_user($apidata['api_arg'], $apidata);
-
- if (empty($user)) {
- $this->clientError(_('No such user!'), 404,
- $apidata['content-type']);
- return;
- }
-
- $profile = $user->getProfile();
- $sitename = common_config('site', 'name');
- $title = sprintf(_("%s and friends"), $user->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:FriendsTimeline:" . $user->id;
- $link = common_local_url('all',
- array('nickname' => $user->nickname));
- $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'),
- $user->nickname, $sitename);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- if (!empty($this->auth_user) && $this->auth_user->id == $user->id) {
- $notice = $user->noticeInbox(($page-1)*$count,
- $count, $since_id, $max_id, $since);
- } else {
- $notice = $user->noticesWithFriends(($page-1)*$count,
- $count, $since_id, $max_id, $since);
- }
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link, $subtitle);
- break;
- case 'atom':
- if (isset($apidata['api_arg'])) {
- $selfuri = common_root_url() .
- 'api/statuses/friends_timeline/' .
- $apidata['api_arg'] . '.atom';
- } else {
- $selfuri = common_root_url() .
- 'api/statuses/friends_timeline.atom';
- }
- $this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, null, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
-
- }
-
- function home_timeline($args, $apidata)
- {
- call_user_func(array($this, 'friends_timeline'), $args, $apidata);
- }
-
- function user_timeline($args, $apidata)
- {
- parent::handle($args);
-
- $this->auth_user = $apidata['user'];
- $user = $this->get_user($apidata['api_arg'], $apidata);
-
- if (empty($user)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $profile = $user->getProfile();
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("%s timeline"), $user->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:UserTimeline:".$user->id;
- $link = common_local_url('showstream',
- array('nickname' => $user->nickname));
- $subtitle = sprintf(_('Updates from %1$s on %2$s!'),
- $user->nickname, $sitename);
-
- # FriendFeed's SUP protocol
- # Also added RSS and Atom feeds
-
- $suplink = common_local_url('sup', null, null, $user->id);
- header('X-SUP-ID: '.$suplink);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- $notice = $user->getNotices(($page-1)*$count,
- $count, $since_id, $max_id, $since);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link,
- $subtitle, $suplink);
- break;
- case 'atom':
- if (isset($apidata['api_arg'])) {
- $selfuri = common_root_url() .
- 'api/statuses/user_timeline/' .
- $apidata['api_arg'] . '.atom';
- } else {
- $selfuri = common_root_url() .
- 'api/statuses/user_timeline.atom';
- }
- $this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, $suplink, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
-
- }
-
- function update($args, $apidata)
- {
- parent::handle($args);
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- $this->clientError(_('This method requires a POST.'),
- 400, $apidata['content-type']);
- return;
- }
-
- $user = $apidata['user']; // Always the auth user
-
- $status = $this->trimmed('status');
- $source = $this->trimmed('source');
- $in_reply_to_status_id =
- intval($this->trimmed('in_reply_to_status_id'));
- $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api');
-
- if (empty($source) || in_array($source, $reserved_sources)) {
- $source = 'api';
- }
-
- if (empty($status)) {
-
- // XXX: Note: In this case, Twitter simply returns '200 OK'
- // No error is given, but the status is not posted to the
- // user's timeline. Seems bad. Shouldn't we throw an
- // errror? -- Zach
- return;
-
- } else {
-
- $status_shortened = common_shorten_links($status);
-
- if (mb_strlen($status_shortened) > 140) {
-
- // XXX: Twitter truncates anything over 140, flags the status
- // as "truncated." Sending this error may screw up some clients
- // that assume Twitter will truncate for them. Should we just
- // truncate too? -- Zach
- $this->clientError(_('That\'s too long. Max notice size is 140 chars.'),
- $code = 406, $apidata['content-type']);
- return;
- }
- }
-
- // Check for commands
- $inter = new CommandInterpreter();
- $cmd = $inter->handle_command($user, $status_shortened);
-
- if ($cmd) {
-
- if ($this->supported($cmd)) {
- $cmd->execute(new Channel());
- }
-
- // cmd not supported? Twitter just returns your latest status.
- // And, it returns your last status whether the cmd was successful
- // or not!
- $n = $user->getCurrentNotice();
- $apidata['api_arg'] = $n->id;
- } else {
-
- $reply_to = null;
-
- if ($in_reply_to_status_id) {
-
- // check whether notice actually exists
- $reply = Notice::staticGet($in_reply_to_status_id);
-
- if ($reply) {
- $reply_to = $in_reply_to_status_id;
- } else {
- $this->clientError(_('Not found'), $code = 404,
- $apidata['content-type']);
- return;
- }
- }
-
- $notice = Notice::saveNew($user->id,
- html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'),
- $source, 1, $reply_to);
-
- if (is_string($notice)) {
- $this->serverError($notice, 500, $apidata['content-type']);
- return;
- }
-
- common_broadcast_notice($notice);
- $apidata['api_arg'] = $notice->id;
- }
-
- $this->show($args, $apidata);
- }
-
- function mentions($args, $apidata)
- {
- parent::handle($args);
-
- $user = $this->get_user($apidata['api_arg'], $apidata);
- $this->auth_user = $apidata['user'];
-
- if (empty($user)) {
- $this->clientError(_('No such user!'), 404,
- $apidata['content-type']);
- return;
- }
-
- $profile = $user->getProfile();
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_('%1$s / Updates mentioning %2$s'),
- $sitename, $user->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:Mentions:".$user->id;
- $link = common_local_url('replies',
- array('nickname' => $user->nickname));
- $subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'),
- $sitename, $user->nickname, $profile->getBestName());
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- $notice = $user->getReplies(($page-1)*$count,
- $count, $since_id, $max_id, $since);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link, $subtitle);
- break;
- case 'atom':
- $selfuri = common_root_url() .
- ltrim($_SERVER['QUERY_STRING'], 'p=');
- $this->show_atom_timeline($notice, $title, $id, $link, $subtitle,
- null, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
-
- }
-
- function replies($args, $apidata)
- {
- call_user_func(array($this, 'mentions'), $args, $apidata);
- }
-
- function show($args, $apidata)
- {
- parent::handle($args);
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- // 'id' is an undocumented parameter in Twitter's API. Several
- // clients make use of it, so we support it too.
-
- // show.json?id=12345 takes precedence over /show/12345.json
-
- $this->auth_user = $apidata['user'];
- $notice_id = $this->trimmed('id');
-
- if (empty($notice_id)) {
- $notice_id = $apidata['api_arg'];
- }
-
- $notice = Notice::staticGet((int)$notice_id);
-
- if ($notice) {
- if ($apidata['content-type'] == 'xml') {
- $this->show_single_xml_status($notice);
- } elseif ($apidata['content-type'] == 'json') {
- $this->show_single_json_status($notice);
- }
- } else {
- // XXX: Twitter just sets a 404 header and doens't bother
- // to return an err msg
- $this->clientError(_('No status with that ID found.'),
- 404, $apidata['content-type']);
- }
- }
-
- function destroy($args, $apidata)
- {
- parent::handle($args);
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- // Check for RESTfulness
- if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) {
- // XXX: Twitter just prints the err msg, no XML / JSON.
- $this->clientError(_('This method requires a POST or DELETE.'),
- 400, $apidata['content-type']);
- return;
- }
-
- $user = $apidata['user']; // Always the auth user
- $notice_id = $apidata['api_arg'];
- $notice = Notice::staticGet($notice_id);
-
- if (empty($notice)) {
- $this->clientError(_('No status found with that ID.'),
- 404, $apidata['content-type']);
- return;
- }
-
- if ($user->id == $notice->profile_id) {
- $replies = new Reply;
- $replies->get('notice_id', $notice_id);
- $replies->delete();
- $notice->delete();
-
- if ($apidata['content-type'] == 'xml') {
- $this->show_single_xml_status($notice);
- } elseif ($apidata['content-type'] == 'json') {
- $this->show_single_json_status($notice);
- }
- } else {
- $this->clientError(_('You may not delete another user\'s status.'),
- 403, $apidata['content-type']);
- }
-
- }
-
- function friends($args, $apidata)
- {
- parent::handle($args);
- $includeStatuses= !(array_key_exists('lite', $args) and $args['lite']);
- return $this->subscriptions($apidata, 'subscribed', 'subscriber', false, $includeStatuses);
- }
-
- function friendsIDs($args, $apidata)
- {
- parent::handle($args);
- return $this->subscriptions($apidata, 'subscribed', 'subscriber', true);
- }
-
- function followers($args, $apidata)
- {
- parent::handle($args);
- $includeStatuses= !(array_key_exists('lite', $args) and $args['lite']);
- return $this->subscriptions($apidata, 'subscriber', 'subscribed', false, $includeStatuses);
- }
-
- function followersIDs($args, $apidata)
- {
- parent::handle($args);
- return $this->subscriptions($apidata, 'subscriber', 'subscribed', true);
- }
-
- function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false, $includeStatuses=true)
- {
- $this->auth_user = $apidata['user'];
- $user = $this->get_user($apidata['api_arg'], $apidata);
-
- if (empty($user)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $profile = $user->getProfile();
-
- $sub = new Subscription();
- $sub->$user_attr = $profile->id;
-
- $sub->orderBy('created DESC');
-
- // Normally, page 100 friends at a time
-
- if (!$onlyIDs) {
- $page = $this->arg('page', 1);
- $count = $this->arg('count', 100);
- $sub->limit(($page-1)*$count, $count);
- } else {
-
- // If we're just looking at IDs, return
- // ALL of them, unless the user specifies a page,
- // in which case, return 500 per page.
-
- $page = $this->arg('page');
- if (!empty($page)) {
- if ($page < 1) {
- $page = 1;
- }
- $count = 500;
- $sub->limit(($page-1)*$count, $count);
- }
- }
-
- $others = array();
-
- if ($sub->find()) {
- while ($sub->fetch()) {
- $others[] = Profile::staticGet($sub->$other_attr);
- }
- } else {
- // user has no followers
- }
-
- $type = $apidata['content-type'];
-
- $this->init_document($type);
-
- if ($onlyIDs) {
- $this->showIDs($others, $type);
- } else {
- $this->show_profiles($others, $type, $includeStatuses);
- }
-
- $this->end_document($type);
- }
-
- function show_profiles($profiles, $type, $includeStatuses)
- {
- switch ($type) {
- case 'xml':
- $this->elementStart('users', array('type' => 'array'));
- foreach ($profiles as $profile) {
- $this->show_profile($profile,$type,null,$includeStatuses);
- }
- $this->elementEnd('users');
- break;
- case 'json':
- $arrays = array();
- foreach ($profiles as $profile) {
- $arrays[] = $this->twitter_user_array($profile, $includeStatuses);
- }
- print json_encode($arrays);
- break;
- default:
- $this->clientError(_('unsupported file type'));
- }
- }
-
- function showIDs($profiles, $type)
- {
- switch ($type) {
- case 'xml':
- $this->elementStart('ids');
- foreach ($profiles as $profile) {
- $this->element('id', null, $profile->id);
- }
- $this->elementEnd('ids');
- break;
- case 'json':
- $ids = array();
- foreach ($profiles as $profile) {
- $ids[] = (int)$profile->id;
- }
- print json_encode($ids);
- break;
- default:
- $this->clientError(_('unsupported file type'));
- }
- }
-
- function featured($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), $code=501);
- }
-
- function supported($cmd)
- {
- $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand',
- 'FavCommand', 'OnCommand', 'OffCommand');
-
- if (in_array(get_class($cmd), $cmdlist)) {
- return true;
- }
-
- return false;
- }
-
-}
diff --git a/actions/twitapistatusnet.php b/actions/twitapistatusnet.php
deleted file mode 100644
index 490f11dce..000000000
--- a/actions/twitapistatusnet.php
+++ /dev/null
@@ -1,175 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * StatusNet-only extensions to the Twitter-like API
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category Twitter
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @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/twitterapi.php';
-
-/**
- * StatusNet-specific API methods
- *
- * This class handles all /statusnet/ API methods.
- *
- * @category Twitter
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @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/
- */
-
-class TwitapistatusnetAction extends TwitterapiAction
-{
- /**
- * A version stamp for the API
- *
- * Returns a version number for this version of StatusNet, which
- * should make things a bit easier for upgrades.
- * URL: http://identi.ca/api/statusnet/version.(xml|json)
- * Formats: xml, json
- *
- * @param array $args Web arguments
- * @param array $apidata Twitter API data
- *
- * @return void
- *
- * @see ApiAction::process_command()
- */
-
- function version($args, $apidata)
- {
- parent::handle($args);
- switch ($apidata['content-type']) {
- case 'xml':
- $this->init_document('xml');
- $this->element('version', null, STATUSNET_VERSION);
- $this->end_document('xml');
- break;
- case 'json':
- $this->init_document('json');
- print '"'.STATUSNET_VERSION.'"';
- $this->end_document('json');
- break;
- default:
- $this->clientError(_('API method not found!'), $code=404);
- }
- }
-
- /**
- * Dump of configuration variables
- *
- * Gives a full dump of configuration variables for this instance
- * of StatusNet, minus variables that may be security-sensitive (like
- * passwords).
- * URL: http://identi.ca/api/statusnet/config.(xml|json)
- * Formats: xml, json
- *
- * @param array $args Web arguments
- * @param array $apidata Twitter API data
- *
- * @return void
- *
- * @see ApiAction::process_command()
- */
-
- function config($args, $apidata)
- {
- static $keys = array('site' => array('name', 'server', 'theme', 'path', 'fancy', 'language',
- 'email', 'broughtby', 'broughtbyurl', 'closed',
- 'inviteonly', 'private'),
- 'license' => array('url', 'title', 'image'),
- 'nickname' => array('featured'),
- 'throttle' => array('enabled', 'count', 'timespan'),
- 'xmpp' => array('enabled', 'server', 'user'));
-
- parent::handle($args);
-
- switch ($apidata['content-type']) {
- case 'xml':
- $this->init_document('xml');
- $this->elementStart('config');
- // XXX: check that all sections and settings are legal XML elements
- foreach ($keys as $section => $settings) {
- $this->elementStart($section);
- foreach ($settings as $setting) {
- $value = common_config($section, $setting);
- if (is_array($value)) {
- $value = implode(',', $value);
- } else if ($value === false) {
- $value = 'false';
- } else if ($value === true) {
- $value = 'true';
- }
- $this->element($setting, null, $value);
- }
- $this->elementEnd($section);
- }
- $this->elementEnd('config');
- $this->end_document('xml');
- break;
- case 'json':
- $result = array();
- foreach ($keys as $section => $settings) {
- $result[$section] = array();
- foreach ($settings as $setting) {
- $result[$section][$setting] = common_config($section, $setting);
- }
- }
- $this->init_document('json');
- $this->show_json_objects($result);
- $this->end_document('json');
- break;
- default:
- $this->clientError(_('API method not found!'), $code=404);
- }
- }
-
- /**
- * WADL description of the API
- *
- * Gives a WADL description of the API provided by this version of the
- * software.
- *
- * @param array $args Web arguments
- * @param array $apidata Twitter API data
- *
- * @return void
- *
- * @see ApiAction::process_command()
- */
-
- function wadl($args, $apidata)
- {
- parent::handle($args);
- $this->serverError(_('API method under construction.'), 501);
- }
-
-}
diff --git a/actions/twitapitags.php b/actions/twitapitags.php
deleted file mode 100644
index 0bcc55d37..000000000
--- a/actions/twitapitags.php
+++ /dev/null
@@ -1,113 +0,0 @@
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * StatusNet extensions to the Twitter-like API for groups
- *
- * PHP version 5
- *
- * LICENCE: This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * @category Twitter
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Zach Copley <zach@status.net>
- * @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') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once INSTALLDIR.'/lib/twitterapi.php';
-
-/**
- * Group-specific API methods
- *
- * This class handles StatusNet group API methods.
- *
- * @category Twitter
- * @package StatusNet
- * @author Craig Andrews <candrews@integralblue.com>
- * @author Zach Copley <zach@status.net>
- * @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/
- */
-
- class TwitapitagsAction extends TwitterapiAction
- {
-
- function timeline($args, $apidata)
- {
- parent::handle($args);
-
- common_debug("in tags api action");
-
- $this->auth_user = $apidata['user'];
- $tag = $apidata['api_arg'];
-
- if (empty($tag)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("Notices tagged with %s"), $tag);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:TagTimeline:".$tag;
- $link = common_local_url('tag',
- array('tag' => $tag));
- $subtitle = sprintf(_('Updates tagged with %1$s on %2$s!'),
- $tag, $sitename);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- # XXX: support max_id, since_id, and since arguments
- $notice = Notice_tag::getStream($tag, ($page-1)*$count, $count + 1);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link, $subtitle);
- break;
- case 'atom':
- if (isset($apidata['api_arg'])) {
- $selfuri = common_root_url() .
- 'api/statusnet/tags/timeline/' .
- $apidata['api_arg'] . '.atom';
- } else {
- $selfuri = common_root_url() .
- 'api/statusnet/tags/timeline.atom';
- }
- $this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, null, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
- }
-
-}
diff --git a/actions/twitapitrends.php b/actions/twitapitrends.php
index 83ab28f35..779405e6d 100644
--- a/actions/twitapitrends.php
+++ b/actions/twitapitrends.php
@@ -31,7 +31,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once INSTALLDIR.'/lib/twitterapi.php';
+require_once INSTALLDIR.'/lib/api.php';
/**
* Returns the top ten queries that are currently trending
@@ -42,10 +42,10 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
- * @see TwitterapiAction
+ * @see ApiAction
*/
-class TwitapitrendsAction extends TwitterapiAction
+class TwitapitrendsAction extends ApiAction
{
var $callback;
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
deleted file mode 100644
index 703fa6754..000000000
--- a/actions/twitapiusers.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/*
- * StatusNet - the distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, StatusNet, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-if (!defined('STATUSNET') && !defined('LACONICA')) {
- exit(1);
-}
-
-require_once(INSTALLDIR.'/lib/twitterapi.php');
-
-class TwitapiusersAction extends TwitterapiAction
-{
-
- function show($args, $apidata)
- {
- parent::handle($args);
-
- if (!in_array($apidata['content-type'], array('xml', 'json'))) {
- $this->clientError(_('API method not found!'), $code = 404);
- return;
- }
-
- $user = null;
- $email = $this->arg('email');
-
- // XXX: email field deprecated in Twitter's API
-
- if ($email) {
- $user = User::staticGet('email', $email);
- } else {
- $user = $this->get_user($apidata['api_arg'], $apidata);
- }
-
- if (empty($user)) {
- $this->clientError(_('Not found.'), 404, $apidata['content-type']);
- return;
- }
-
- $profile = $user->getProfile();
-
- if (!$profile) {
- common_server_error(_('User has no profile.'));
- return;
- }
-
- $twitter_user = $this->twitter_user_array($user->getProfile(), true);
-
- if ($apidata['content-type'] == 'xml') {
- $this->init_document('xml');
- $this->show_twitter_xml_user($twitter_user);
- $this->end_document('xml');
- } elseif ($apidata['content-type'] == 'json') {
- $this->init_document('json');
- $this->show_json_objects($twitter_user);
- $this->end_document('json');
- } else {
-
- // This is in case 'show' was called via /account/verify_credentials
- // without a format (xml or json).
- header('Content-Type: text/html; charset=utf-8');
- print 'Authorized';
- }
-
- }
-}
diff --git a/actions/updateprofile.php b/actions/updateprofile.php
index 9a4cf8e46..3cec9523c 100644
--- a/actions/updateprofile.php
+++ b/actions/updateprofile.php
@@ -1,5 +1,16 @@
<?php
-/*
+/**
+ * Handle an updateprofile action
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@@ -19,165 +30,54 @@
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
+/**
+ * Handle an updateprofile action
+ *
+ * @category Action
+ * @package Laconica
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@controlyourself.ca>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://laconi.ca/
+ */
class UpdateprofileAction extends Action
{
-
- function handle($args)
- {
- parent::handle($args);
- try {
- common_remove_magic_from_request();
- $req = OAuthRequest::from_request('POST', common_local_url('updateprofile'));
- # Note: server-to-server function!
- $server = omb_oauth_server();
- list($consumer, $token) = $server->verify_request($req);
- if ($this->update_profile($req, $consumer, $token)) {
- header('HTTP/1.1 200 OK');
- header('Content-type: text/plain');
- print "omb_version=".OMB_VERSION_01;
- }
- } catch (OAuthException $e) {
- $this->serverError($e->getMessage());
- return;
- }
- }
- function update_profile($req, $consumer, $token)
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
{
- $version = $req->get_parameter('omb_version');
- if ($version != OMB_VERSION_01) {
- $this->clientError(_('Unsupported OMB version'), 400);
+ parent::prepare($argarray);
+ $license = $_POST['omb_listenee_license'];
+ $site_license = common_config('license', 'url');
+ if (!common_compatible_license($license, $site_license)) {
+ $this->clientError(sprintf(_('Listenee stream license ‘%s’ is not '.
+ 'compatible with site license ‘%s’.'),
+ $license, $site_license));
return false;
}
- # First, check to see if listenee exists
- $listenee = $req->get_parameter('omb_listenee');
- $remote = Remote_profile::staticGet('uri', $listenee);
- if (!$remote) {
- $this->clientError(_('Profile unknown'), 404);
- return false;
- }
- # Second, check to see if they should be able to post updates!
- # We see if there are any subscriptions to that remote user with
- # the given token.
-
- $sub = new Subscription();
- $sub->subscribed = $remote->id;
- $sub->token = $token->key;
- if (!$sub->find(true)) {
- $this->clientError(_('You did not send us that profile'), 403);
- return false;
- }
-
- $profile = Profile::staticGet('id', $remote->id);
- if (!$profile) {
- # This one is our fault
- $this->serverError(_('Remote profile with no matching profile'), 500);
- return false;
- }
- $nickname = $req->get_parameter('omb_listenee_nickname');
- if ($nickname && !Validate::string($nickname, array('min_length' => 1,
- 'max_length' => 64,
- 'format' => NICKNAME_FMT))) {
- $this->clientError(_('Nickname must have only lowercase letters and numbers and no spaces.'));
- return false;
- }
- $license = $req->get_parameter('omb_listenee_license');
- if ($license && !common_valid_http_url($license)) {
- $this->clientError(sprintf(_("Invalid license URL '%s'"), $license));
- return false;
- }
- $profile_url = $req->get_parameter('omb_listenee_profile');
- if ($profile_url && !common_valid_http_url($profile_url)) {
- $this->clientError(sprintf(_("Invalid profile URL '%s'."), $profile_url));
- return false;
- }
- # optional stuff
- $fullname = $req->get_parameter('omb_listenee_fullname');
- if ($fullname && mb_strlen($fullname) > 255) {
- $this->clientError(_("Full name is too long (max 255 chars)."));
- return false;
- }
- $homepage = $req->get_parameter('omb_listenee_homepage');
- if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
- $this->clientError(sprintf(_("Invalid homepage '%s'"), $homepage));
- return false;
- }
- $bio = $req->get_parameter('omb_listenee_bio');
- if ($bio && mb_strlen($bio) > 140) {
- $this->clientError(_("Bio is too long (max 140 chars)."));
- return false;
- }
- $location = $req->get_parameter('omb_listenee_location');
- if ($location && mb_strlen($location) > 255) {
- $this->clientError(_("Location is too long (max 255 chars)."));
- return false;
- }
- $avatar = $req->get_parameter('omb_listenee_avatar');
- if ($avatar) {
- if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
- $this->clientError(sprintf(_("Invalid avatar URL '%s'"), $avatar));
- return false;
- }
- $size = @getimagesize($avatar);
- if (!$size) {
- $this->clientError(sprintf(_("Can't read avatar URL '%s'"), $avatar));
- return false;
- }
- if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) {
- $this->clientError(sprintf(_("Wrong size image at '%s'"), $avatar));
- return false;
- }
- if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
- IMAGETYPE_PNG))) {
- $this->clientError(sprintf(_("Wrong image type for '%s'"), $avatar));
- return false;
- }
- }
-
- $orig_profile = clone($profile);
+ return true;
+ }
- /* Use values even if they are an empty string. Parsing an empty string in
- updateProfile is the specified way of clearing a parameter in OMB. */
- if (!is_null($nickname)) {
- $profile->nickname = $nickname;
- }
- if (!is_null($profile_url)) {
- $profile->profileurl = $profile_url;
- }
- if (!is_null($fullname)) {
- $profile->fullname = $fullname;
- }
- if (!is_null($homepage)) {
- $profile->homepage = $homepage;
- }
- if (!is_null($bio)) {
- $profile->bio = $bio;
- }
- if (!is_null($location)) {
- $profile->location = $location;
- }
+ function handle($args)
+ {
+ parent::handle($args);
- if (!$profile->update($orig_profile)) {
- $this->serverError(_('Could not save new profile info'), 500);
- return false;
- } else {
- if ($avatar) {
- $temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
- copy($avatar, $temp_filename);
- $imagefile = new ImageFile($profile->id, $temp_filename);
- $filename = Avatar::filename($profile->id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
- if (!$profile->setOriginal($filename)) {
- $this->serverError(_('Could not save avatar info'), 500);
- return false;
- }
- }
- return true;
+ try {
+ $srv = new OMB_Service_Provider(null, omb_oauth_datastore(),
+ omb_oauth_server());
+ $srv->handleUpdateProfile();
+ } catch (Exception $e) {
+ $this->serverError($e->getMessage());
+ return;
}
}
}
diff --git a/actions/userauthorization.php b/actions/userauthorization.php
index a9ac1f256..dc59e6c94 100644
--- a/actions/userauthorization.php
+++ b/actions/userauthorization.php
@@ -1,5 +1,16 @@
<?php
-/*
+/**
+ * Let the user authorize a remote subscription request
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
@@ -19,7 +30,9 @@
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
+require_once INSTALLDIR.'/extlib/libomb/profile.php';
define('TIMESTAMP_THRESHOLD', 300);
class UserauthorizationAction extends Action
@@ -32,46 +45,58 @@ class UserauthorizationAction extends Action
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- # CSRF protection
+ /* Use a session token for CSRF protection. */
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
- $params = $this->getStoredParams();
- $this->showForm($params, _('There was a problem with your session token. '.
- 'Try again, please.'));
+ $srv = $this->getStoredParams();
+ $this->showForm($srv->getRemoteUser(), _('There was a problem ' .
+ 'with your session token. Try again, ' .
+ 'please.'));
return;
}
- # We've shown the form, now post user's choice
+ /* We've shown the form, now post user's choice. */
$this->sendAuthorization();
} else {
if (!common_logged_in()) {
- # Go log in, and then come back
+ /* 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;
+ }
+
+ $user = common_current_user();
+ $profile = $user->getProfile();
+ if (!$profile) {
+ common_log_db_error($user, 'SELECT', __FILE__);
+ $this->serverError(_('User without matching profile'));
return;
}
+ /* TODO: If no token is passed the user should get a prompt to enter
+ it according to OAuth Core 1.0. */
try {
- $this->validateRequest();
- $this->storeParams($_GET);
- $this->showForm($_GET);
- } catch (OAuthException $e) {
+ $this->validateOmb();
+ $srv = new OMB_Service_Provider(
+ profile_to_omb_profile($user->uri, $profile),
+ omb_oauth_datastore());
+
+ $remote_user = $srv->handleUserAuth();
+ } catch (Exception $e) {
$this->clearParams();
$this->clientError($e->getMessage());
return;
}
+ $this->storeParams($srv);
+ $this->showForm($remote_user);
}
}
function showForm($params, $error=null)
{
$this->params = $params;
- $this->error = $error;
+ $this->error = $error;
$this->showPage();
}
@@ -83,23 +108,24 @@ class UserauthorizationAction extends Action
function showPageNotice()
{
$this->element('p', null, _('Please check these details to make sure '.
- 'that you want to subscribe to this user\'s notices. '.
- 'If you didn\'t just ask to subscribe to someone\'s notices, '.
- 'click "Reject".'));
+ 'that you want to subscribe to this ' .
+ 'user’s notices. If you didn’t just ask ' .
+ 'to subscribe to someone’s notices, '.
+ 'click “Reject”.'));
}
function showContent()
{
$params = $this->params;
- $nickname = $params['omb_listenee_nickname'];
- $profile = $params['omb_listenee_profile'];
- $license = $params['omb_listenee_license'];
- $fullname = $params['omb_listenee_fullname'];
- $homepage = $params['omb_listenee_homepage'];
- $bio = $params['omb_listenee_bio'];
- $location = $params['omb_listenee_location'];
- $avatar = $params['omb_listenee_avatar'];
+ $nickname = $params->getNickname();
+ $profile = $params->getProfileURL();
+ $license = $params->getLicenseURL();
+ $fullname = $params->getFullname();
+ $homepage = $params->getHomepage();
+ $bio = $params->getBio();
+ $location = $params->getLocation();
+ $avatar = $params->getAvatarURL();
$this->elementStart('div', array('class' => 'profile'));
$this->elementStart('div', 'entity_profile vcard');
@@ -176,11 +202,14 @@ class UserauthorizationAction extends Action
'id' => 'userauthorization',
'class' => 'form_user_authorization',
'name' => 'userauthorization',
- 'action' => common_local_url('userauthorization')));
+ 'action' => common_local_url(
+ 'userauthorization')));
$this->hidden('token', common_session_token());
- $this->submit('accept', _('Accept'), 'submit accept', null, _('Subscribe to this user'));
- $this->submit('reject', _('Reject'), 'submit reject', null, _('Reject this subscription'));
+ $this->submit('accept', _('Accept'), 'submit accept', null,
+ _('Subscribe to this user'));
+ $this->submit('reject', _('Reject'), 'submit reject', null,
+ _('Reject this subscription'));
$this->elementEnd('form');
$this->elementEnd('li');
$this->elementEnd('ul');
@@ -190,191 +219,27 @@ class UserauthorizationAction extends Action
function sendAuthorization()
{
- $params = $this->getStoredParams();
+ $srv = $this->getStoredParams();
- if (!$params) {
+ if (is_null($srv)) {
$this->clientError(_('No authorization request!'));
return;
}
- $callback = $params['oauth_callback'];
-
- if ($this->arg('accept')) {
- if (!$this->authorizeToken($params)) {
- $this->clientError(_('Error authorizing token'));
- }
- if (!$this->saveRemoteProfile($params)) {
- $this->clientError(_('Error saving remote profile'));
- }
- if (!$callback) {
- $this->showAcceptMessage($params['oauth_token']);
- } else {
- $newparams = array();
- $newparams['oauth_token'] = $params['oauth_token'];
- $newparams['omb_version'] = OMB_VERSION_01;
- $user = User::staticGet('uri', $params['omb_listener']);
- $profile = $user->getProfile();
- if (!$profile) {
- common_log_db_error($user, 'SELECT', __FILE__);
- $this->serverError(_('User without matching profile'));
- return;
- }
- $newparams['omb_listener_nickname'] = $user->nickname;
- $newparams['omb_listener_profile'] = common_local_url('showstream',
- array('nickname' => $user->nickname));
- if (!is_null($profile->fullname)) {
- $newparams['omb_listener_fullname'] = $profile->fullname;
- }
- if (!is_null($profile->homepage)) {
- $newparams['omb_listener_homepage'] = $profile->homepage;
- }
- if (!is_null($profile->bio)) {
- $newparams['omb_listener_bio'] = $profile->bio;
- }
- if (!is_null($profile->location)) {
- $newparams['omb_listener_location'] = $profile->location;
- }
- $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
- if ($avatar) {
- $newparams['omb_listener_avatar'] = $avatar->url;
- }
- $parts = array();
- foreach ($newparams as $k => $v) {
- $parts[] = $k . '=' . OAuthUtil::urlencode_rfc3986($v);
- }
- $query_string = implode('&', $parts);
- $parsed = parse_url($callback);
- $url = $callback . (($parsed['query']) ? '&' : '?') . $query_string;
- common_redirect($url, 303);
- }
- } else {
- if (!$callback) {
- $this->showRejectMessage();
- } else {
- # XXX: not 100% sure how to signal failure... just redirect without token?
- common_redirect($callback, 303);
- }
- }
- }
-
- function authorizeToken(&$params)
- {
- $token_field = $params['oauth_token'];
- $rt = new Token();
- $rt->tok = $token_field;
- $rt->type = 0;
- $rt->state = 0;
- if ($rt->find(true)) {
- $orig_rt = clone($rt);
- $rt->state = 1; # Authorized but not used
- if ($rt->update($orig_rt)) {
- return true;
- }
- }
- return false;
- }
-
- # XXX: refactor with similar code in finishremotesubscribe.php
-
- function saveRemoteProfile(&$params)
- {
- # FIXME: we should really do this when the consumer comes
- # back for an access token. If they never do, we've got stuff in a
- # weird state.
-
- $nickname = $params['omb_listenee_nickname'];
- $fullname = $params['omb_listenee_fullname'];
- $profile_url = $params['omb_listenee_profile'];
- $homepage = $params['omb_listenee_homepage'];
- $bio = $params['omb_listenee_bio'];
- $location = $params['omb_listenee_location'];
- $avatar_url = $params['omb_listenee_avatar'];
-
- $listenee = $params['omb_listenee'];
- $remote = Remote_profile::staticGet('uri', $listenee);
-
- if ($remote) {
- $exists = true;
- $profile = Profile::staticGet($remote->id);
- $orig_remote = clone($remote);
- $orig_profile = clone($profile);
- } else {
- $exists = false;
- $remote = new Remote_profile();
- $remote->uri = $listenee;
- $profile = new Profile();
- }
-
- $profile->nickname = $nickname;
- $profile->profileurl = $profile_url;
-
- if (!is_null($fullname)) {
- $profile->fullname = $fullname;
- }
- if (!is_null($homepage)) {
- $profile->homepage = $homepage;
- }
- if (!is_null($bio)) {
- $profile->bio = $bio;
- }
- if (!is_null($location)) {
- $profile->location = $location;
+ $accepted = $this->arg('accept');
+ try {
+ list($val, $token) = $srv->continueUserAuth($accepted);
+ } catch (Exception $e) {
+ $this->clientError($e->getMessage());
+ return;
}
-
- if ($exists) {
- $profile->update($orig_profile);
+ if ($val !== false) {
+ common_redirect($val, 303);
+ } elseif ($accepted) {
+ $this->showAcceptMessage($token);
} else {
- $profile->created = DB_DataObject_Cast::dateTime(); # current time
- $id = $profile->insert();
- if (!$id) {
- return false;
- }
- $remote->id = $id;
+ $this->showRejectMessage();
}
-
- if ($exists) {
- if (!$remote->update($orig_remote)) {
- return false;
- }
- } else {
- $remote->created = DB_DataObject_Cast::dateTime(); # current time
- if (!$remote->insert()) {
- return false;
- }
- }
-
- if ($avatar_url) {
- if (!$this->addAvatar($profile, $avatar_url)) {
- return false;
- }
- }
-
- $user = common_current_user();
-
- $sub = new Subscription();
- $sub->subscriber = $user->id;
- $sub->subscribed = $remote->id;
- $sub->token = $params['oauth_token']; # NOTE: request token, not valid for use!
- $sub->created = DB_DataObject_Cast::dateTime(); # current time
-
- if (!$sub->insert()) {
- return false;
- }
-
- return true;
- }
-
- function addAvatar($profile, $url)
- {
- $temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
- copy($url, $temp_filename);
- $imagefile = new ImageFile($profile->id, $temp_filename);
- $filename = Avatar::filename($profile->id,
- image_type_to_extension($imagefile->type),
- null,
- common_timestamp());
- rename($temp_filename, Avatar::path($filename));
- return $profile->setOriginal($filename);
}
function showAcceptMessage($tok)
@@ -382,26 +247,28 @@ class UserauthorizationAction extends Action
common_show_header(_('Subscription authorized'));
$this->element('p', null,
_('The subscription has been authorized, but no '.
- 'callback URL was passed. Check with the site\'s instructions for '.
- 'details on how to authorize the subscription. Your subscription token is:'));
+ 'callback URL was passed. Check with the site’s ' .
+ 'instructions for details on how to authorize the ' .
+ 'subscription. Your subscription token is:'));
$this->element('blockquote', 'token', $tok);
common_show_footer();
}
- function showRejectMessage($tok)
+ function showRejectMessage()
{
common_show_header(_('Subscription rejected'));
$this->element('p', null,
_('The subscription has been rejected, but no '.
- 'callback URL was passed. Check with the site\'s instructions for '.
- 'details on how to fully reject the subscription.'));
+ 'callback URL was passed. Check with the site’s ' .
+ 'instructions for details on how to fully reject ' .
+ 'the subscription.'));
common_show_footer();
}
function storeParams($params)
{
common_ensure_session();
- $_SESSION['userauthorizationparams'] = $params;
+ $_SESSION['userauthorizationparams'] = serialize($params);
}
function clearParams()
@@ -413,138 +280,74 @@ class UserauthorizationAction extends Action
function getStoredParams()
{
common_ensure_session();
- $params = $_SESSION['userauthorizationparams'];
+ $params = unserialize($_SESSION['userauthorizationparams']);
return $params;
}
- # Throws an OAuthException if anything goes wrong
-
- function validateRequest()
- {
- /* Find token.
- TODO: If no token is passed the user should get a prompt to enter it
- according to OAuth Core 1.0 */
- $t = new Token();
- $t->tok = $_GET['oauth_token'];
- $t->type = 0;
- if (!$t->find(true)) {
- throw new OAuthException("Invalid request token: " . $_GET['oauth_token']);
- }
-
- $this->validateOmb();
- return true;
- }
-
function validateOmb()
{
- foreach (array('omb_version', 'omb_listener', 'omb_listenee',
- 'omb_listenee_profile', 'omb_listenee_nickname',
- 'omb_listenee_license') as $param)
- {
- if (!isset($_GET[$param]) || is_null($_GET[$param])) {
- throw new OAuthException("Required parameter '$param' not found");
- }
- }
- # Now, OMB stuff
- $version = $_GET['omb_version'];
- if ($version != OMB_VERSION_01) {
- throw new OAuthException("OpenMicroBlogging version '$version' not supported");
- }
$listener = $_GET['omb_listener'];
+ $listenee = $_GET['omb_listenee'];
+ $nickname = $_GET['omb_listenee_nickname'];
+ $profile = $_GET['omb_listenee_profile'];
+
$user = User::staticGet('uri', $listener);
if (!$user) {
- throw new OAuthException("Listener URI '$listener' not found here");
- }
- $cur = common_current_user();
- if ($cur->id != $user->id) {
- throw new OAuthException("Can't add for another user!");
- }
- $listenee = $_GET['omb_listenee'];
- if (!Validate::uri($listenee) &&
- !common_valid_tag($listenee)) {
- throw new OAuthException("Listenee URI '$listenee' not a recognizable URI");
+ throw new Exception(sprintf(_('Listener URI ‘%s’ not found here'),
+ $listener));
}
+
if (strlen($listenee) > 255) {
- throw new OAuthException("Listenee URI '$listenee' too long");
+ throw new Exception(sprintf(_('Listenee URI ‘%s’ is too long.'),
+ $listenee));
}
$other = User::staticGet('uri', $listenee);
if ($other) {
- throw new OAuthException("Listenee URI '$listenee' is local user");
+ throw new Exception(sprintf(_('Listenee URI ‘%s’ is a local user.'),
+ $listenee));
}
$remote = Remote_profile::staticGet('uri', $listenee);
if ($remote) {
- $sub = new Subscription();
+ $sub = new Subscription();
$sub->subscriber = $user->id;
$sub->subscribed = $remote->id;
if ($sub->find(true)) {
- throw new OAuthException("Already subscribed to user!");
+ throw new Exception('You are already subscribed to this user.');
}
}
- $nickname = $_GET['omb_listenee_nickname'];
- if (!Validate::string($nickname, array('min_length' => 1,
- 'max_length' => 64,
- 'format' => NICKNAME_FMT))) {
- throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
- }
- $profile = $_GET['omb_listenee_profile'];
- if (!common_valid_http_url($profile)) {
- throw new OAuthException("Invalid profile URL '$profile'.");
- }
- if ($profile == common_local_url('showstream', array('nickname' => $nickname))) {
- throw new OAuthException("Profile URL '$profile' is for a local user.");
- }
+ if ($profile == common_profile_url($nickname)) {
+ throw new Exception(sprintf(_('Profile URL ‘%s’ is for a local user.'),
+ $profile));
- $license = $_GET['omb_listenee_license'];
- if (!common_valid_http_url($license)) {
- throw new OAuthException("Invalid license URL '$license'.");
}
+
+ $license = $_GET['omb_listenee_license'];
$site_license = common_config('license', 'url');
if (!common_compatible_license($license, $site_license)) {
- throw new OAuthException("Listenee stream license '$license' not compatible with site license '$site_license'.");
- }
- # optional stuff
- $fullname = $_GET['omb_listenee_fullname'];
- if ($fullname && mb_strlen($fullname) > 255) {
- throw new OAuthException("Full name '$fullname' too long.");
- }
- $homepage = $_GET['omb_listenee_homepage'];
- if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
- throw new OAuthException("Invalid homepage '$homepage'");
- }
- $bio = $_GET['omb_listenee_bio'];
- if ($bio && mb_strlen($bio) > 140) {
- throw new OAuthException("Bio too long '$bio'");
- }
- $location = $_GET['omb_listenee_location'];
- if ($location && mb_strlen($location) > 255) {
- throw new OAuthException("Location too long '$location'");
+ throw new Exception(sprintf(_('Listenee stream license ‘%s’ is not ' .
+ 'compatible with site license ‘%s’.'),
+ $license, $site_license));
}
+
$avatar = $_GET['omb_listenee_avatar'];
if ($avatar) {
if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
- throw new OAuthException("Invalid avatar URL '$avatar'");
+ throw new Exception(sprintf(_('Avatar URL ‘%s’ is not valid.'),
+ $avatar));
}
$size = @getimagesize($avatar);
if (!$size) {
- throw new OAuthException("Can't read avatar URL '$avatar'");
- }
- if ($size[0] != AVATAR_PROFILE_SIZE || $size[1] != AVATAR_PROFILE_SIZE) {
- throw new OAuthException("Wrong size image at '$avatar'");
+ throw new Exception(sprintf(_('Can’t read avatar URL ‘%s’.'),
+ $avatar));
}
if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
IMAGETYPE_PNG))) {
- throw new OAuthException("Wrong image type for '$avatar'");
+ throw new Exception(sprintf(_('Wrong image type for avatar URL '.
+ '‘%s’.'), $avatar));
}
}
- $callback = $_GET['oauth_callback'];
- if ($callback && !common_valid_http_url($callback)) {
- throw new OAuthException("Invalid callback URL '$callback'");
- }
- if ($callback && $callback == common_local_url('finishremotesubscribe')) {
- throw new OAuthException("Callback URL '$callback' is for local site.");
- }
}
-}
+} \ No newline at end of file
diff --git a/actions/userrss.php b/actions/userrss.php
index fa6d588cd..19e610551 100644
--- a/actions/userrss.php
+++ b/actions/userrss.php
@@ -25,7 +25,6 @@ require_once(INSTALLDIR.'/lib/rssaction.php');
class UserrssAction extends Rss10Action
{
- var $user = null;
var $tag = null;
function prepare($args)
@@ -39,6 +38,7 @@ class UserrssAction extends Rss10Action
$this->clientError(_('No such user.'));
return false;
} else {
+ $this->notices = $this->getNotices($this->limit);
return true;
}
}
@@ -64,9 +64,8 @@ class UserrssAction extends Rss10Action
function getNotices($limit=0)
{
-
$user = $this->user;
-
+
if (is_null($user)) {
return null;
}
diff --git a/actions/xrds.php b/actions/xrds.php
index def10e4cf..8ba89fec0 100644
--- a/actions/xrds.php
+++ b/actions/xrds.php
@@ -1,7 +1,7 @@
<?php
/**
- * XRDS for OpenID
+ * XRDS for OpenMicroBlogging
*
* PHP version 5
*
@@ -34,9 +34,11 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
}
require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
+require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
/**
- * XRDS for OpenID
+ * XRDS for OpenMicroBlogging
*
* @category Action
* @package StatusNet
@@ -52,7 +54,7 @@ class XrdsAction extends Action
*
* @return boolean true
*/
- function isReadOnly($args)
+ function isReadOnly()
{
return true;
}
@@ -85,89 +87,31 @@ class XrdsAction extends Action
*/
function showXrds($user)
{
- header('Content-Type: application/xrds+xml');
- $this->startXML();
- $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
+ $srv = new OMB_Service_Provider(profile_to_omb_profile($user->uri,
+ $user->getProfile()));
+ /* Use libomb’s default XRDS Writer. */
+ $xrds_writer = null;
+ $srv->writeXRDS(new Laconica_XRDS_Mapper(), $xrds_writer);
+ }
+}
- $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
- 'xml:id' => 'oauth',
- 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
- 'version' => '2.0'));
- $this->element('Type', null, 'xri://$xrds*simple');
- $this->showService(OAUTH_ENDPOINT_REQUEST,
- common_local_url('requesttoken'),
- array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
- array(OAUTH_HMAC_SHA1),
- $user->uri);
- $this->showService(OAUTH_ENDPOINT_AUTHORIZE,
- common_local_url('userauthorization'),
- array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
- array(OAUTH_HMAC_SHA1));
- $this->showService(OAUTH_ENDPOINT_ACCESS,
- common_local_url('accesstoken'),
- array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
- array(OAUTH_HMAC_SHA1));
- $this->showService(OAUTH_ENDPOINT_RESOURCE,
- null,
- array(OAUTH_AUTH_HEADER, OAUTH_POST_BODY),
- array(OAUTH_HMAC_SHA1));
- $this->elementEnd('XRD');
+class Laconica_XRDS_Mapper implements OMB_XRDS_Mapper
+{
+ protected $urls;
- // XXX: decide whether to include user's ID/nickname in postNotice URL
- $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
- 'xml:id' => 'omb',
- 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
- 'version' => '2.0'));
- $this->element('Type', null, 'xri://$xrds*simple');
- $this->showService(OMB_ENDPOINT_POSTNOTICE,
- common_local_url('postnotice'));
- $this->showService(OMB_ENDPOINT_UPDATEPROFILE,
- common_local_url('updateprofile'));
- $this->elementEnd('XRD');
- $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
- 'version' => '2.0'));
- $this->element('Type', null, 'xri://$xrds*simple');
- $this->showService(OAUTH_DISCOVERY,
- '#oauth');
- $this->showService(OMB_NAMESPACE,
- '#omb');
- $this->elementEnd('XRD');
- $this->elementEnd('XRDS');
- $this->endXML();
+ public function __construct()
+ {
+ $this->urls = array(
+ OAUTH_ENDPOINT_REQUEST => 'requesttoken',
+ OAUTH_ENDPOINT_AUTHORIZE => 'userauthorization',
+ OAUTH_ENDPOINT_ACCESS => 'accesstoken',
+ OMB_ENDPOINT_POSTNOTICE => 'postnotice',
+ OMB_ENDPOINT_UPDATEPROFILE => 'updateprofile');
}
- /**
- * Show service.
- *
- * @param string $type XRDS type
- * @param string $uri URI
- * @param array $params type parameters, null by default
- * @param array $sigs type signatures, null by default
- * @param string $localId local ID, null by default
- *
- * @return void
- */
- function showService($type, $uri, $params=null, $sigs=null, $localId=null)
+ public function getURL($action)
{
- $this->elementStart('Service');
- if ($uri) {
- $this->element('URI', null, $uri);
- }
- $this->element('Type', null, $type);
- if ($params) {
- foreach ($params as $param) {
- $this->element('Type', null, $param);
- }
- }
- if ($sigs) {
- foreach ($sigs as $sig) {
- $this->element('Type', null, $sig);
- }
- }
- if ($localId) {
- $this->element('LocalID', null, $localId);
- }
- $this->elementEnd('Service');
+ return common_local_url($this->urls[$action]);
}
}
-
+?>