Qvitter API changes (thanks hannes2peer)

I implemented changes from quitter.se's new API that their front-end qvitter
uses, https://github.com/hannesmannerheim/qvitter/blob/master/api-changes-1.1.1/CHANGES

However I left out the URL shortening commens, since I believe whatever behaviour
they experienced that caused them to implement this was a bug (or many) and should
be fixed in their proper areas and that shortening should not be entirely left
out in API calls.
This commit is contained in:
Mikael Nordfeldth 2013-10-06 21:30:29 +02:00
parent 753019baf2
commit 34a6624452
37 changed files with 1274 additions and 80 deletions

View File

@ -0,0 +1,252 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Register account
*
* 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiAccountRegisterAction extends ApiAction
{
/**
* Has there been an error?
*/
var $error = null;
/**
* Have we registered?
*/
var $registered = false;
/**
* Are we processing an invite?
*/
var $invite = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
parent::prepare($args);
$this->code = $this->trimmed('code');
if (empty($this->code)) {
common_ensure_session();
if (array_key_exists('invitecode', $_SESSION)) {
$this->code = $_SESSION['invitecode'];
}
}
if (common_config('site', 'inviteonly') && empty($this->code)) {
// TRANS: Client error displayed when trying to register to an invite-only site without an invitation.
$this->clientError(_('Sorry, only invited people can register.'),404,'json');
return false;
}
if (!empty($this->code)) {
$this->invite = Invitation::staticGet('code', $this->code);
if (empty($this->invite)) {
// TRANS: Client error displayed when trying to register to an invite-only site without a valid invitation.
$this->clientError(_('Sorry, invalid invitation code.'),404,'json');
return false;
}
// Store this in case we need it
common_ensure_session();
$_SESSION['invitecode'] = $this->code;
}
return true;
}
/**
* Handle the request
*
* @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;
} else {
$nickname = $this->trimmed('nickname');
$email = $this->trimmed('email');
$fullname = $this->trimmed('fullname');
$homepage = $this->trimmed('homepage');
$bio = $this->trimmed('bio');
$location = $this->trimmed('location');
// We don't trim these... whitespace is OK in a password!
$password = $this->arg('password');
$confirm = $this->arg('confirm');
// invitation code, if any
$code = $this->trimmed('code');
if ($code) {
$invite = Invitation::staticGet($code);
}
if (common_config('site', 'inviteonly') && !($code && $invite)) {
// TRANS: Client error displayed when trying to register to an invite-only site without an invitation.
$this->clientError(_('Sorry, only invited people can register.'),404,'json');
return;
}
// Input scrubbing
try {
$nickname = Nickname::normalize($nickname);
} catch (NicknameException $e) {
$this->showForm($e->getMessage());
}
$email = common_canonical_email($email);
if ($email && !Validate::email($email, common_config('email', 'check_domain'))) {
// TRANS: Form validation error displayed when trying to register without a valid e-mail address.
$this->clientError(_('Not a valid email address.'),404,'json');
} else if ($this->nicknameExists($nickname)) {
// TRANS: Form validation error displayed when trying to register with an existing nickname.
$this->clientError(_('Nickname already in use. Try another one.'),404,'json');
} else if (!User::allowed_nickname($nickname)) {
// TRANS: Form validation error displayed when trying to register with an invalid nickname.
$this->clientError(_('Not a valid nickname.'),404,'json');
} else if ($this->emailExists($email)) {
// TRANS: Form validation error displayed when trying to register with an already registered e-mail address.
$this->clientError(_('Email address already exists.'),404,'json');
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
!Validate::uri($homepage,
array('allowed_schemes' =>
array('http', 'https')))) {
// TRANS: Form validation error displayed when trying to register with an invalid homepage URL.
$this->clientError(_('Homepage is not a valid URL.'),404,'json');
return;
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
// TRANS: Form validation error displayed when trying to register with a too long full name.
$this->clientError(_('Full name is too long (maximum 255 characters).'),404,'json');
return;
} else if (Profile::bioTooLong($bio)) {
// TRANS: Form validation error on registration page when providing too long a bio text.
// TRANS: %d is the maximum number of characters for bio; used for plural.
$this->clientError(sprintf(_m('Bio is too long (maximum %d character).',
'Bio is too long (maximum %d characters).',
Profile::maxBio()),
Profile::maxBio()),404,'json');
return;
} else if (!is_null($location) && mb_strlen($location) > 255) {
// TRANS: Form validation error displayed when trying to register with a too long location.
$this->clientError(_('Location is too long (maximum 255 characters).'),404,'json');
return;
} else if (strlen($password) < 6) {
// TRANS: Form validation error displayed when trying to register with too short a password.
$this->clientError(_('Password must be 6 or more characters.'),404,'json');
return;
} else if ($password != $confirm) {
// TRANS: Form validation error displayed when trying to register with non-matching passwords.
$this->clientError(_('Passwords do not match.'),404,'json');
} else {
// annoy spammers
sleep(7);
if ($user = User::register(array('nickname' => $nickname,
'password' => $password,
'email' => $email,
'fullname' => $fullname,
'homepage' => $homepage,
'bio' => $bio,
'location' => $location,
'code' => $code))) {
if (!$user) {
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
$this->clientError(_('Invalid username or password.'),404,'json');
return;
}
Event::handle('EndRegistrationTry', array($this));
$this->initDocument('json');
$this->showJsonObjects($this->twitterUserArray($user->getProfile()));
$this->endDocument('json');
} else {
// TRANS: Form validation error displayed when trying to register with an invalid username or password.
$this->clientError(_('Invalid username or password.'),404,'json');
}
}
}
}
/**
* Does the given nickname already exist?
*
* Checks a canonical nickname against the database.
*
* @param string $nickname nickname to check
*
* @return boolean true if the nickname already exists
*/
function nicknameExists($nickname)
{
$user = User::staticGet('nickname', $nickname);
return is_object($user);
}
/**
* Does the given email address already exist?
*
* Checks a canonical email address against the database.
*
* @param string $email email address to check
*
* @return boolean true if the address already exists
*/
function emailExists($email)
{
$email = common_canonical_email($email);
if (!$email || strlen($email) == 0) {
return false;
}
$user = User::staticGet('email', $email);
return is_object($user);
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update a user's background color
*
* 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiAccountUpdateBackgroundColorAction extends ApiAuthAction
{
var $backgroundcolor = 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->backgroundcolor = $this->trimmed('backgroundcolor');
return true;
}
/**
* Handle the request
*
* Try to save the user's colors in her design. Create a new design
* if the user doesn't already have one.
*
* @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;
}
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->backgroundcolor);
if($validhex === false || $validhex == 0) {
$this->clientError(_('Not a valid hex color.'),404,'json');
return;
}
// save the new color
$original = clone($this->user);
$this->user->backgroundcolor = $this->backgroundcolor;
if (!$this->user->update($original)) {
$this->clientError(_('Error updating user.'),404,'json');
return;
}
$profile = $this->user->getProfile();
if (empty($profile)) {
$this->clientError(_('User has no profile.'),'json');
return;
}
$twitter_user = $this->twitterUserArray($profile, true);
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}

View File

@ -0,0 +1,104 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Update a user's link color
*
* 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiAccountUpdateLinkColorAction extends ApiAuthAction
{
var $linkcolor = 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->linkcolor = $this->trimmed('linkcolor');
return true;
}
/**
* Handle the request
*
* Try to save the user's colors in her design. Create a new design
* if the user doesn't already have one.
*
* @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;
}
$validhex = preg_match('/^[a-f0-9]{6}$/i',$this->linkcolor);
if($validhex === false || $validhex == 0) {
$this->clientError(_('Not a valid hex color.'),404,'json');
return;
}
// save the new color
$original = clone($this->user);
$this->user->linkcolor = $this->linkcolor;
if (!$this->user->update($original)) {
$this->clientError(_('Error updating user.'),404,'json');
return;
}
$profile = $this->user->getProfile();
if (empty($profile)) {
$this->clientError(_('User has no profile.'),'json');
return;
}
$twitter_user = $this->twitterUserArray($profile, true);
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}

101
actions/apiattachment.php Normal file
View File

@ -0,0 +1,101 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a notice's attachment
*
* 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Show a notice's attachment
*
*/
class ApiAttachmentAction extends ApiAuthAction
{
const MAXCOUNT = 100;
var $original = null;
var $cnt = self::MAXCOUNT;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
parent::prepare($args);
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);
$file = new File();
$file->selectAdd(); // clears it
$file->selectAdd('url');
$file->id = $this->trimmed('id');
$url = $file->fetchAll('url');
$file_txt = '';
if(strstr($url[0],'.html')) {
$file_txt['txt'] = file_get_contents(str_replace('://quitter.se','://127.0.0.1',$url[0]));
$file_txt['body_start'] = strpos($file_txt['txt'],'<body>')+6;
$file_txt['body_end'] = strpos($file_txt['txt'],'</body>');
$file_txt = substr($file_txt['txt'],$file_txt['body_start'],$file_txt['body_end']-$file_txt['body_start']);
}
$this->initDocument('json');
$this->showJsonObjects($file_txt);
$this->endDocument('json');
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}

117
actions/apicheckhub.php Normal file
View File

@ -0,0 +1,117 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show a notice's attachment
*
* 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Check if a url have a push-hub, i.e. if it is possible to subscribe
*
*/
class ApiCheckHubAction extends ApiAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
parent::prepare($args);
$this->url = urldecode($args['url']);
if (!$this->url) {
$this->clientError(_('No URL.'), 403, 'json');
return;
}
if (!Validate::uri(
$this->url, array(
'allowed_schemes' =>
array('http', 'https')
)
)) {
$this->clientError(_('Invalid URL.'), 403, 'json');
return;
}
return true;
}
/**
* Handle the request
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
$discover = new FeedDiscovery();
try {
$feeduri = $discover->discoverFromURL($this->url);
if($feeduri) {
$huburi = $discover->getHubLink();
}
} catch (FeedSubNoFeedException $e) {
$this->clientError(_('No feed found'), 403, 'json');
return;
} catch (FeedSubBadResponseException $e) {
$this->clientError(_('No hub found'), 403, 'json');
return;
}
$hub_status = array();
if ($huburi) {
$hub_status = array('huburi' => $huburi);
}
$this->initDocument('json');
$this->showJsonObjects($hub_status);
$this->endDocument('json');
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}

View File

@ -0,0 +1,69 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Check nickname
*
* Returns 1 if nickname is ok, 0 if not
*
* 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
class ApiCheckNicknameAction extends ApiAction
{
function prepare($args)
{
parent::prepare($args);
return true;
}
function handle($args)
{
parent::handle($args);
$nickname = $this->trimmed('nickname');
if ($this->nicknameExists($nickname)) {
$nickname_ok = 0;
} else if (!User::allowed_nickname($nickname)) {
$nickname_ok = 0; }
else {
$nickname_ok = 1;
}
$this->initDocument('json');
$this->showJsonObjects($nickname_ok);
$this->endDocument('json');
}
function nicknameExists($nickname)
{
$user = User::staticGet('nickname', $nickname);
return is_object($user);
}
}

View File

@ -75,9 +75,7 @@ class ApiconversationAction extends ApiAuthAction
404);
}
$profile = Profile::current();
$stream = new ConversationNoticeStream($convId, $profile);
$stream = new ConversationNoticeStream($convId, $this->scoped);
$notice = $stream->getNotices(($this->page-1) * $this->count,
$this->count,

View File

@ -0,0 +1,95 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show an external 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Ouputs information for a user, specified by ID or screen name.
* The user's most recent status will be returned inline.
*/
class ApiExternalProfileShowAction extends ApiPrivateAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$profileurl = urldecode($this->arg('profileurl'));
$this->profile = Profile::staticGet('profileurl', $profileurl);
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->profile)) {
// TRANS: Client error displayed when requesting profile information for a non-existing profile.
$this->clientError(_('Profile not found.'), 404, 'json');
return;
}
$twitter_user = $this->twitterUserArray($this->profile, true);
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}

View File

@ -33,8 +33,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Tests for the existence of friendship between two users. Will return true if
* user_a follows user_b, otherwise will return false.

191
actions/apigroupadmins.php Normal file
View File

@ -0,0 +1,191 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* List a group's admins
*
* 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 GNUSocial
* @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>
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @copyright 2009 StatusNet, Inc.
* @copyright 2009 Free Software Foundation, Inc http://www.fsf.org
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) {
exit(1);
}
/**
* List 20 newest admins of the group specified by name or ID.
*
* @category API
* @package GNUSocial
* @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>
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
class ApiGroupAdminsAction extends ApiPrivateAuthAction
{
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'));
if (empty($this->group)) {
// TRANS: Client error displayed trying to show group membership on a non-existing group.
$this->clientError(_('Group not found.'), 404, $this->format);
return false;
}
$this->profiles = $this->getProfiles();
return true;
}
/**
* Handle the request
*
* Show the admin 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(
// TRANS: Client error displayed when coming across a non-supported API method.
_('API method not found.'),
404,
$this->format
);
break;
}
}
/**
* Fetch the admins of a group
*
* @return array $profiles list of profiles
*/
function getProfiles()
{
$profiles = array();
$profile = $this->group->getAdmins(
($this->page - 1) * $this->count,
$this->count,
$this->since_id,
$this->max_id
);
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_user_cache_hash($this->auth_user),
common_language(),
$this->group->id,
strtotime($this->profiles[0]->created),
strtotime($this->profiles[$last]->created))
)
. '"';
}
return null;
}
}

View File

@ -35,8 +35,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns of the lastest 20 groups for the site
*

View File

@ -35,8 +35,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* List 20 newest members of the group specified by name or ID.
*

View File

@ -35,8 +35,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Outputs detailed information about the group specified by ID
*

View File

@ -32,8 +32,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the string "ok" in the requested format with a 200 OK HTTP status code.
*

View File

@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
/**
* Action for outputting search results in Twitter compatible Atom
* format.

View File

@ -20,19 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Search
* @package StatusNet
* @package GNUSocial
* @author Zach Copley <zach@status.net>
* @copyright 2008-2010 StatusNet, Inc.
* @copyright 2013 Free Software Foundation, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
* @link http://www.gnu.org/software/social/
*/
if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Action handler for Twitter-compatible API search
@ -89,12 +85,6 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
$this->since_id = $this->trimmed('since_id');
$this->geocode = $this->trimmed('geocode');
if (!empty($this->auth_user)) {
$this->auth_profile = $this->auth_user->getProfile();
} else {
$this->auth_profile = null;
}
return true;
}
@ -123,15 +113,15 @@ class ApiSearchJSONAction extends ApiPrivateAuthAction
// TODO: Support search operators like from: and to:, boolean, etc.
if (preg_match('/^#([\pL\pN_\-\.]{1,64})$/ue', $q)) {
$stream = new TagNoticeStream(substr($q, 1), $this->auth_profile);
$stream = new TagNoticeStream(substr($q, 1), $this->scoped);
} else if ($this->isAnURL($q)) {
$canon = File_redirection::_canonUrl($q);
$file = File::getKV('url', $canon);
if (!empty($file)) {
$stream = new FileNoticeStream($file, $this->auth_profile);
$stream = new FileNoticeStream($file, $this->scoped);
}
} else {
$stream = new SearchNoticeStream($q, $this->auth_profile);
$stream = new SearchNoticeStream($q, $this->scoped);
}
if (empty($stream)) {

134
actions/apistatusesfavs.php Normal file
View File

@ -0,0 +1,134 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Show up to 100 favs of a notice
*
* 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 GNUSocial
* @author Hannes Mannerheim <h@nnesmannerhe.im>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://www.gnu.org/software/social/
*/
if (!defined('GNUSOCIAL')) { exit(1); }
/**
* Show up to 100 favs of a notice
*
*/
class ApiStatusesFavsAction extends ApiAuthAction
{
const MAXCOUNT = 100;
var $original = null;
var $cnt = self::MAXCOUNT;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
parent::prepare($args);
$id = $this->trimmed('id');
$this->original = Notice::staticGet('id', $id);
if (empty($this->original)) {
// TRANS: Client error displayed trying to display redents of a non-exiting notice.
$this->clientError(_('No such notice.'),
400, $this->format);
return false;
}
$cnt = $this->trimmed('count');
if (empty($cnt) || !is_integer($cnt)) {
$cnt = 100;
} else {
$this->cnt = min((int)$cnt, self::MAXCOUNT);
}
return true;
}
/**
* Handle the request
*
* Get favs and return them as json object
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$fave = new Fave();
$fave->selectAdd();
$fave->selectAdd('user_id');
$fave->notice_id = $this->original->id;
$fave->orderBy('modified');
if (!is_null($this->cnt)) {
$fave->limit(0, $this->cnt);
}
$ids = $fave->fetchAll('user_id');
// get nickname and profile image
$ids_with_profile_data = array();
$i=0;
foreach($ids as $id) {
$profile = Profile::staticGet('id', $id);
$ids_with_profile_data[$i]['user_id'] = $id;
$ids_with_profile_data[$i]['nickname'] = $profile->nickname;
$ids_with_profile_data[$i]['fullname'] = $profile->fullname;
$ids_with_profile_data[$i]['profileurl'] = $profile->profileurl;
$profile = new Profile();
$profile->id = $id;
$avatarurl = $profile->avatarUrl(24);
$ids_with_profile_data[$i]['avatarurl'] = $avatarurl;
$i++;
}
$this->initDocument('json');
$this->showJsonObjects($ids_with_profile_data);
$this->endDocument('json');
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}

View File

@ -38,8 +38,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the notice specified by id as a Twitter-style status and inline user
*

View File

@ -32,8 +32,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns a version number for this version of StatusNet, which
* should make things a bit easier for upgrades.

View File

@ -35,8 +35,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the most recent notices (default 20) posted to the group specified by ID
*

View File

@ -35,7 +35,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
require_once INSTALLDIR . '/lib/atomlistnoticefeed.php';
/**

View File

@ -38,8 +38,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the most recent notices (default 20) posted by everybody
*

View File

@ -35,8 +35,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Returns the 20 most recent notices tagged by a given tag
*
@ -179,7 +177,9 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
$notice = Notice_tag::getStream(
$this->tag,
($this->page - 1) * $this->count,
$this->count + 1
$this->count + 1,
$this->since_id,
$this->max_id
);
while ($notice->fetch()) {

View File

@ -229,7 +229,8 @@ class ApiTimelineUserAction extends ApiBareAuthAction
$notice = $this->user->getNotices(($this->page-1) * $this->count,
$this->count + 1,
$this->since_id,
$this->max_id);
$this->max_id,
$this->scoped);
while ($notice->fetch()) {
if (count($notices) < $this->count) {

View File

@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/apiprivateauth.php';
/**
* Returns the top ten queries that are currently trending
*

View File

@ -31,8 +31,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Ouputs avatar URL for a user, specified by screen name.
* Unlike most API endpoints, this returns an HTTP redirect rather than direct data.

View File

@ -34,8 +34,6 @@ if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Ouputs information for a user, specified by ID or screen name.
* The user's most recent status will be returned inline.

View File

@ -211,6 +211,11 @@ class Notice extends Managed_DataObject
return $result;
}
public function getUri()
{
return $this->uri;
}
/**
* Extract #hashtags from this notice's content and save them to the database.
*/
@ -417,7 +422,7 @@ class Notice extends Managed_DataObject
$repeat = Notice::getKV('id', $repeat_of);
if (empty($repeat)) {
if (!($repeat instanceof Notice)) {
// TRANS: Client exception thrown in notice when trying to repeat a missing or deleted notice.
throw new ClientException(_('Cannot repeat; original notice is missing or deleted.'));
}
@ -439,7 +444,7 @@ class Notice extends Managed_DataObject
throw new ClientException(_('Cannot repeat a notice you cannot read.'), 403);
}
if ($profile->hasRepeated($repeat->id)) {
if ($profile->hasRepeated($repeat)) {
// TRANS: Client error displayed when trying to repeat an already repeated notice.
throw new ClientException(_('You already repeated that notice.'));
}
@ -1710,9 +1715,9 @@ class Notice extends Managed_DataObject
// favorite and repeated
if (!empty($cur)) {
$noticeInfoAttr['favorite'] = ($cur->hasFave($this)) ? "true" : "false";
$cp = $cur->getProfile();
$noticeInfoAttr['repeated'] = ($cp->hasRepeated($this->id)) ? "true" : "false";
$noticeInfoAttr['favorite'] = ($cp->hasFave($this)) ? "true" : "false";
$noticeInfoAttr['repeated'] = ($cp->hasRepeated($this)) ? "true" : "false";
}
if (!empty($this->repeat_of)) {

View File

@ -211,9 +211,9 @@ class Profile extends Managed_DataObject
return $stream->getNotices($offset, $limit, $since_id, $max_id);
}
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0)
function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, Profile $scoped=null)
{
$stream = new ProfileNoticeStream($this);
$stream = new ProfileNoticeStream($this, $scoped);
return $stream->getNotices($offset, $limit, $since_id, $max_id);
}
@ -1157,12 +1157,13 @@ class Profile extends Managed_DataObject
return $result;
}
function hasRepeated($notice_id)
// FIXME: Can't put Notice typing here due to ArrayWrapper
public function hasRepeated($notice)
{
// XXX: not really a pkey, but should work
$notice = Notice::pkeyGet(array('profile_id' => $this->id,
'repeat_of' => $notice_id));
'repeat_of' => $notice->id));
return !empty($notice);
}

View File

@ -210,7 +210,12 @@ class User_group extends Managed_DataObject
return $members;
}
function getMemberCount()
public function getAdminCount()
{
return $this->getAdmins()->N;
}
public function getMemberCount()
{
$key = sprintf("group:member_count:%d", $this->id);

View File

@ -62,7 +62,7 @@ class Action extends HTMLOutputter // lawsuit
protected $menus = true;
protected $needLogin = false;
// The currently scoped profile
// The currently scoped profile (normally Profile::current; from $this->auth_user for API)
protected $scoped = null;
// Messages to the front-end user

View File

@ -214,7 +214,23 @@ class ApiAction extends Action
$twitter_user['location'] = ($profile->location) ? $profile->location : null;
$twitter_user['description'] = ($profile->bio) ? $profile->bio : null;
$twitter_user['profile_image_url'] = $profile->avatarUrl(AVATAR_STREAM_SIZE);
// TODO: avatar url template (example.com/user/avatar?size={x}x{y})
$twitter_user['profile_image_url'] = Avatar::urlByProfile($profile, AVATAR_STREAM_SIZE);
// START introduced by qvitter API, not necessary for StatusNet API
$twitter_user['profile_image_url_profile_size'] = Avatar::urlByProfile($profile, AVATAR_PROFILE_SIZE);
try {
$avatar = Avatar::getUploaded($profile);
$origurl = $avatar->displayUrl();
} catch (Exception $e) {
$origurl = $twitter_user['profile_image_url_profile_size'];
}
$twitter_user['profile_image_url_original'] = $origurl;
$twitter_user['groups_count'] = $profile->getGroups(0, null)->N;
foreach (array('linkcolor', 'backgroundcolor') as $key) {
$twitter_user[$key] = Profile_prefs::getConfigData($profile, 'theme', $key);
}
// END introduced by qvitter API, not necessary for StatusNet API
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
$twitter_user['protected'] = (!empty($user) && $user->private_stream) ? true : false;
@ -263,7 +279,7 @@ class ApiAction extends Action
if ($get_notice) {
$notice = $profile->getCurrentNotice();
if ($notice) {
if ($notice instanceof Notice) {
// don't get user!
$twitter_user['status'] = $this->twitterStatusArray($notice, false);
}
@ -299,8 +315,12 @@ class ApiAction extends Action
$twitter_status['text'] = $notice->content;
$twitter_status['truncated'] = false; # Not possible on StatusNet
$twitter_status['created_at'] = $this->dateTwitter($notice->created);
$twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ?
intval($notice->reply_to) : null;
try {
$in_reply_to = $notice->getParent()->id;
} catch (Exception $e) {
$in_reply_to = null;
}
$twitter_status['in_reply_to_status_id'] = $in_reply_to;
$source = null;
@ -317,6 +337,7 @@ class ApiAction extends Action
}
}
$twitter_status['uri'] = $notice->getUri();
$twitter_status['source'] = $source;
$twitter_status['id'] = intval($notice->id);
@ -343,10 +364,12 @@ class ApiAction extends Action
$twitter_status['geo'] = null;
}
if (isset($this->auth_user)) {
$twitter_status['favorited'] = $this->auth_user->hasFave($notice);
if (!is_null($this->scoped)) {
$twitter_status['favorited'] = $this->scoped->hasFave($notice);
$twitter_status['repeated'] = $this->scoped->hasRepeated($notice);
} else {
$twitter_status['favorited'] = false;
$twitter_status['repeated'] = false;
}
// Enclosures
@ -399,6 +422,7 @@ class ApiAction extends Action
);
}
$twitter_group['admin_count'] = $group->getAdminCount();
$twitter_group['member_count'] = $group->getMemberCount();
$twitter_group['original_logo'] = $group->original_logo;
$twitter_group['homepage_logo'] = $group->homepage_logo;
@ -1550,6 +1574,8 @@ class ApiAction extends Action
} else if (self::is_decimal($id)) {
return User_group::getKV('id', $id);
} else if ($this->arg('uri')) { // FIXME: move this into empty($id) check?
return User_group::getKV('uri', urldecode($this->arg('uri')));
} else {
return User_group::getForNickname($id);
}

View File

@ -232,14 +232,7 @@ class ResultItem
$this->id = $this->notice->id;
$this->from_user_id = $this->profile->id;
$user = $this->profile->getUser();
if (empty($user)) {
// Gonna have to do till we can detect it
$this->iso_language_code = common_config('site', 'language');
} else {
$this->iso_language_code = $user->language;
}
$this->iso_language_code = Profile_prefs::getConfigData($this->profile, 'site', 'language');
$this->source = $this->getSourceLink($this->notice->source);

View File

@ -693,7 +693,7 @@ class NoticeListItem extends Widget
$user->id != $this->notice->profile_id) {
$this->out->text(' ');
$profile = $user->getProfile();
if ($profile->hasRepeated($this->notice->id)) {
if ($profile->hasRepeated($this->notice)) {
$this->out->element('span', array('class' => 'repeated',
// TRANS: Title for repeat form status in notice list when a notice has been repeated.
'title' => _('Notice repeated.')),

View File

@ -460,6 +460,41 @@ class Router
'id' => '[0-9]+',
'format' => '(xml|json)'));
// START qvitter API additions
$m->connect('api/statuses/favs/:id.json',
array('action' => 'ApiStatusesFavs',
'id' => '[0-9]+'));
$m->connect('api/attachment/:id.json',
array('action' => 'ApiAttachment',
'id' => '[0-9]+'));
$m->connect('api/checkhub.json',
array('action' => 'ApiCheckHub'));
$m->connect('api/externalprofile/show.json',
array('action' => 'ApiExternalProfileShow'));
$m->connect('api/statusnet/groups/admins/:id.:format',
array('action' => 'ApiGroupAdmins',
'id' => Nickname::INPUT_FMT,
'format' => '(xml|json)'));
$m->connect('api/account/update_link_color.json',
array('action' => 'ApiAccountUpdateLinkColor'));
$m->connect('api/account/update_background_color.json',
array('action' => 'ApiAccountUpdateBackgroundColor'));
$m->connect('api/account/register.json',
array('action' => 'ApiAccountRegister'));
$m->connect('api/check_nickname.json',
array('action' => 'ApiCheckNickname'));
// END qvitter API additions
// users
$m->connect('api/users/show/:id.:format',
@ -773,6 +808,7 @@ class Router
// Tags
$m->connect('api/statusnet/tags/timeline/:tag.:format',
array('action' => 'ApiTimelineTag',
'tag' => self::REGEX_TAG,
'format' => '(xml|json|rss|atom|as)'));
// media related

View File

@ -148,10 +148,10 @@ class SubMirror extends Managed_DataObject
* @param Notice $notice
* @return mixed Notice on successful mirroring, boolean if not
*/
public function mirrorNotice($notice)
public function mirrorNotice(Notice $notice)
{
$profile = Profile::getKV('id', $this->subscriber);
if (!$profile) {
if (!($profile instanceof Profile)) {
common_log(LOG_ERR, "SubMirror plugin skipping auto-repeat of notice $notice->id for missing user $profile->id");
return false;
}
@ -172,9 +172,9 @@ class SubMirror extends Managed_DataObject
* @param Notice $notice
* @return mixed Notice on successful repeat, true if already repeated, false on failure
*/
protected function repeatNotice($profile, $notice)
protected function repeatNotice(Profile $profile, Notice $notice)
{
if($profile->hasRepeated($notice->id)) {
if($profile->hasRepeated($notice)) {
common_log(LOG_INFO, "SubMirror plugin skipping auto-repeat of notice $notice->id for user $profile->id; already repeated.");
return true;
} else {