Merge commit 'mainline/0.9.x' into 0.9.x
This commit is contained in:
commit
02a6006baf
32
EVENTS.txt
32
EVENTS.txt
|
@ -655,3 +655,35 @@ StartUnblockProfile: when we're about to unblock
|
|||
EndUnblockProfile: when an unblock has succeeded
|
||||
- $user: the person doing the unblock
|
||||
- $profile: the person unblocked, can be remote
|
||||
|
||||
StartSubscribe: when a subscription is starting
|
||||
- $user: the person subscribing
|
||||
- $other: the person being subscribed to
|
||||
|
||||
EndSubscribe: when a subscription is finished
|
||||
- $user: the person subscribing
|
||||
- $other: the person being subscribed to
|
||||
|
||||
StartUnsubscribe: when an unsubscribe is starting
|
||||
- $user: the person unsubscribing
|
||||
- $other: the person being unsubscribed from
|
||||
|
||||
EndUnsubscribe: when an unsubscribe is done
|
||||
- $user: the person unsubscribing
|
||||
- $other: the person being unsubscribed to
|
||||
|
||||
StartJoinGroup: when a user is joining a group
|
||||
- $group: the group being joined
|
||||
- $user: the user joining
|
||||
|
||||
EndJoinGroup: when a user finishes joining a group
|
||||
- $group: the group being joined
|
||||
- $user: the user joining
|
||||
|
||||
StartLeaveGroup: when a user is leaving a group
|
||||
- $group: the group being left
|
||||
- $user: the user leaving
|
||||
|
||||
EndLeaveGroup: when a user has left a group
|
||||
- $group: the group being left
|
||||
- $user: the user leaving
|
||||
|
|
|
@ -81,7 +81,7 @@ class AllAction extends ProfileAction
|
|||
function title()
|
||||
{
|
||||
if ($this->page > 1) {
|
||||
return sprintf(_("%1$s and friends, page %2$d"), $this->user->nickname, $this->page);
|
||||
return sprintf(_('%1$s and friends, page %2$d'), $this->user->nickname, $this->page);
|
||||
} else {
|
||||
return sprintf(_("%s and friends"), $this->user->nickname);
|
||||
}
|
||||
|
|
|
@ -82,4 +82,18 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read only?
|
||||
*
|
||||
* @param array $args other arguments
|
||||
*
|
||||
* @return boolean true
|
||||
*
|
||||
**/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -153,7 +153,7 @@ class ApiDirectMessageAction extends ApiAuthAction
|
|||
$this->showJsonDirectMessages();
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
|
|||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
@ -116,7 +116,7 @@ class ApiFavoriteCreateAction extends ApiAuthAction
|
|||
|
||||
if ($this->user->hasFave($this->notice)) {
|
||||
$this->clientError(
|
||||
_('This status is already a favorite!'),
|
||||
_('This status is already a favorite.'),
|
||||
403,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -97,7 +97,7 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
|
|||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
@ -119,7 +119,7 @@ class ApiFavoriteDestroyAction extends ApiAuthAction
|
|||
|
||||
if (!$fave->find(true)) {
|
||||
$this->clientError(
|
||||
_('That status is not a favorite!'),
|
||||
_('That status is not a favorite.'),
|
||||
403,
|
||||
$this->favorite
|
||||
);
|
||||
|
|
|
@ -97,7 +97,7 @@ class ApiFriendshipsCreateAction extends ApiAuthAction
|
|||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -97,7 +97,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
|
|||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
@ -117,7 +117,7 @@ class ApiFriendshipsDestroyAction extends ApiAuthAction
|
|||
|
||||
if ($this->user->id == $this->other->id) {
|
||||
$this->clientError(
|
||||
_("You cannot unfollow yourself!"),
|
||||
_("You cannot unfollow yourself."),
|
||||
403,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -126,7 +126,7 @@ class ApiFriendshipsShowAction extends ApiBareAuthAction
|
|||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(_('API method not found!'), 404);
|
||||
$this->clientError(_('API method not found.'), 404);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ class ApiGroupCreateAction extends ApiAuthAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -111,7 +111,7 @@ class ApiGroupIsMemberAction extends ApiBareAuthAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
400,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -145,14 +145,14 @@ class ApiGroupJoinAction extends ApiAuthAction
|
|||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->show_single_xml_group($this->group);
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -131,14 +131,14 @@ class ApiGroupLeaveAction extends ApiAuthAction
|
|||
|
||||
switch($this->format) {
|
||||
case 'xml':
|
||||
$this->show_single_xml_group($this->group);
|
||||
$this->showSingleXmlGroup($this->group);
|
||||
break;
|
||||
case 'json':
|
||||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -129,7 +129,7 @@ class ApiGroupListAction extends ApiBareAuthAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -117,7 +117,7 @@ class ApiGroupListAllAction extends ApiPrivateAuthAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -103,7 +103,7 @@ class ApiGroupMembershipAction extends ApiPrivateAuthAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -102,7 +102,7 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
|
|||
$this->showSingleJsonGroup($this->group);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), 404, $this->format);
|
||||
$this->clientError(_('API method not found.'), 404, $this->format);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ class ApiHelpTestAction extends ApiPrivateAuthAction
|
|||
$this->endDocument('json');
|
||||
} else {
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
94
actions/apioauthaccesstoken.php
Normal file
94
actions/apioauthaccesstoken.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Exchange an authorized OAuth request token for an access token
|
||||
*
|
||||
* 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 Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Exchange an authorized OAuth request token for an access token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthAccessTokenAction extends ApiOauthAction
|
||||
{
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$datastore = new ApiStatusNetOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
$atok = null;
|
||||
|
||||
try {
|
||||
$req = OAuthRequest::from_request();
|
||||
$atok = $server->fetch_access_token($req);
|
||||
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARN, 'API OAuthException - ' . $e->getMessage());
|
||||
common_debug(var_export($req, true));
|
||||
$this->outputError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($atok)) {
|
||||
common_debug('couldn\'t get access token.');
|
||||
print "Token exchange failed. Has the request token been authorized?\n";
|
||||
} else {
|
||||
print $atok;
|
||||
}
|
||||
}
|
||||
|
||||
function outputError($msg)
|
||||
{
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print $msg . "\n";
|
||||
}
|
||||
}
|
||||
|
376
actions/apioauthauthorize.php
Normal file
376
actions/apioauthauthorize.php
Normal file
|
@ -0,0 +1,376 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* 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 Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Authorize an OAuth request token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthAuthorizeAction extends ApiOauthAction
|
||||
{
|
||||
var $oauth_token;
|
||||
var $callback;
|
||||
var $app;
|
||||
var $nickname;
|
||||
var $password;
|
||||
var $store;
|
||||
|
||||
/**
|
||||
* Is this a read-only action?
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
common_debug("apioauthauthorize");
|
||||
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
$this->password = $this->arg('password');
|
||||
$this->oauth_token = $this->arg('oauth_token');
|
||||
$this->callback = $this->arg('oauth_callback');
|
||||
$this->store = new ApiStatusNetOAuthDataStore();
|
||||
$this->app = $this->store->getAppByRequestToken($this->oauth_token);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle input, produce output
|
||||
*
|
||||
* Switches on request method; either shows the form or handles its input.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
$this->handlePost();
|
||||
|
||||
} else {
|
||||
|
||||
// XXX: make better error messages
|
||||
|
||||
if (empty($this->oauth_token)) {
|
||||
|
||||
common_debug("No request token found.");
|
||||
|
||||
$this->clientError(_('Bad request.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->app)) {
|
||||
common_debug('No app for that token.');
|
||||
$this->clientError(_('Bad request.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$name = $this->app->name;
|
||||
common_debug("Requesting auth for app: " . $name);
|
||||
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
common_debug("handlePost()");
|
||||
|
||||
// check 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. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// check creds
|
||||
|
||||
$user = null;
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$user = common_check_user($this->nickname, $this->password);
|
||||
if (empty($user)) {
|
||||
$this->showForm(_("Invalid nickname / password!"));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$user = common_current_user();
|
||||
}
|
||||
|
||||
if ($this->arg('allow')) {
|
||||
|
||||
// mark the req token as authorized
|
||||
|
||||
$this->store->authorize_token($this->oauth_token);
|
||||
|
||||
// Check to see if there was a previous token associated
|
||||
// with this user/app and kill it. If the user is doing this she
|
||||
// probably doesn't want any old tokens anyway.
|
||||
|
||||
$appUser = Oauth_application_user::getByKeys($user, $this->app);
|
||||
|
||||
if (!empty($appUser)) {
|
||||
$result = $appUser->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($appUser, 'DELETE', __FILE__);
|
||||
throw new ServerException(_('DB error deleting OAuth app user.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// associated the authorized req token with the user and the app
|
||||
|
||||
$appUser = new Oauth_application_user();
|
||||
|
||||
$appUser->profile_id = $user->id;
|
||||
$appUser->application_id = $this->app->id;
|
||||
|
||||
// Note: do not copy the access type from the application.
|
||||
// The access type should always be 0 when the OAuth app
|
||||
// user record has a request token associated with it.
|
||||
// Access type gets assigned once an access token has been
|
||||
// granted. The OAuth app user record then gets updated
|
||||
// with the new access token and access type.
|
||||
|
||||
$appUser->token = $this->oauth_token;
|
||||
$appUser->created = common_sql_now();
|
||||
|
||||
$result = $appUser->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($appUser, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('DB error inserting OAuth app user.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// if we have a callback redirect and provide the token
|
||||
|
||||
// A callback specified in the app setup overrides whatever
|
||||
// is passed in with the request.
|
||||
|
||||
common_debug("Req token is authorized - doing callback");
|
||||
|
||||
if (!empty($this->app->callback_url)) {
|
||||
$this->callback = $this->app->callback_url;
|
||||
}
|
||||
|
||||
if (!empty($this->callback)) {
|
||||
|
||||
// XXX: Need better way to build this redirect url.
|
||||
|
||||
$target_url = $this->getCallback($this->callback,
|
||||
array('oauth_token' => $this->oauth_token));
|
||||
|
||||
common_debug("Doing callback to $target_url");
|
||||
|
||||
common_redirect($target_url, 303);
|
||||
} else {
|
||||
common_debug("callback was empty!");
|
||||
}
|
||||
|
||||
// otherwise inform the user that the rt was authorized
|
||||
|
||||
$this->elementStart('p');
|
||||
|
||||
// XXX: Do OAuth 1.0a verifier code
|
||||
|
||||
$this->raw(sprintf(_("The request token %s has been authorized. " .
|
||||
'Please exchange it for an access token.'),
|
||||
$this->oauth_token));
|
||||
|
||||
$this->elementEnd('p');
|
||||
|
||||
} else if ($this->arg('deny')) {
|
||||
|
||||
$this->elementStart('p');
|
||||
|
||||
$this->raw(sprintf(_("The request token %s has been denied."),
|
||||
$this->oauth_token));
|
||||
|
||||
$this->elementEnd('p');
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($error=null)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showScripts()
|
||||
{
|
||||
parent::showScripts();
|
||||
if (!common_logged_in()) {
|
||||
$this->autofocus('nickname');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('An application would like to connect to your account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the authorization form.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_apioauthauthorize',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('apioauthauthorize')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', array('id' => 'apioauthauthorize_allowdeny'),
|
||||
_('Allow or deny access'));
|
||||
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->hidden('oauth_token', $this->oauth_token);
|
||||
$this->hidden('oauth_callback', $this->callback);
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->elementStart('p');
|
||||
if (!empty($this->app->icon)) {
|
||||
$this->element('img', array('src' => $this->app->icon));
|
||||
}
|
||||
|
||||
$access = ($this->app->access_type & Oauth_application::$writeAccess) ?
|
||||
'access and update' : 'access';
|
||||
|
||||
$msg = _("The application <strong>%1$s</strong> by <strong>%2$s</strong> would like " .
|
||||
"the ability to <strong>%3$s</strong> your account data.");
|
||||
|
||||
$this->raw(sprintf($msg,
|
||||
$this->app->name,
|
||||
$this->app->organization,
|
||||
$access));
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
if (!common_logged_in()) {
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, _('Account'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Nickname'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('password', _('Password'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
}
|
||||
|
||||
$this->element('input', array('id' => 'deny_submit',
|
||||
'class' => 'submit submit form_action-primary',
|
||||
'name' => 'deny',
|
||||
'type' => 'submit',
|
||||
'value' => _('Deny')));
|
||||
|
||||
$this->element('input', array('id' => 'allow_submit',
|
||||
'class' => 'submit submit form_action-secondary',
|
||||
'name' => 'allow',
|
||||
'type' => 'submit',
|
||||
'value' => _('Allow')));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for using the form
|
||||
*
|
||||
* For "remembered" logins, we make the user re-login when they
|
||||
* try to change settings. Different instructions for this case.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Allow or deny access to your account information.');
|
||||
}
|
||||
|
||||
/**
|
||||
* A local menu
|
||||
*
|
||||
* Shows different login/register actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showLocalNav()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
99
actions/apioauthrequesttoken.php
Normal file
99
actions/apioauthrequesttoken.php
Normal file
|
@ -0,0 +1,99 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Get an OAuth request token
|
||||
*
|
||||
* 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 Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Get an OAuth request token
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthRequestTokenAction extends ApiOauthAction
|
||||
{
|
||||
/**
|
||||
* Take arguments for running
|
||||
*
|
||||
* @param array $args $_REQUEST args
|
||||
*
|
||||
* @return boolean success flag
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->callback = $this->arg('oauth_callback');
|
||||
|
||||
if (!empty($this->callback)) {
|
||||
common_debug("callback: $this->callback");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class handler.
|
||||
*
|
||||
* @param array $args array of arguments
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
$datastore = new ApiStatusNetOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
try {
|
||||
$req = OAuthRequest::from_request();
|
||||
$token = $server->fetch_request_token($req);
|
||||
print $token;
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARN, 'API OAuthException - ' . $e->getMessage());
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print $e->getMessage() . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -99,7 +99,7 @@ class ApiStatusesDestroyAction extends ApiAuthAction
|
|||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
|
|||
$this->showJsonTimeline($strm);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ class ApiStatusesShowAction extends ApiPrivateAuthAction
|
|||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,11 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
|||
$this->lat = $this->trimmed('lat');
|
||||
$this->lon = $this->trimmed('long');
|
||||
|
||||
// try to set the source attr from OAuth app
|
||||
if (empty($this->source)) {
|
||||
$this->source = $this->oauth_source;
|
||||
}
|
||||
|
||||
if (empty($this->source) || in_array($this->source, self::$reserved_sources)) {
|
||||
$this->source = 'api';
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ class ApiStatusnetConfigAction extends ApiAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -90,7 +90,7 @@ class ApiStatusnetVersionAction extends ApiPrivateAuthAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -108,7 +108,7 @@ class ApiSubscriptionsAction extends ApiBareAuthAction
|
|||
parent::handle($args);
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ class ApiTimelineFavoritesAction extends ApiBareAuthAction
|
|||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,7 +72,6 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
common_debug("api friends_timeline");
|
||||
$this->user = $this->getTargetUser($this->arg('id'));
|
||||
|
||||
if (empty($this->user)) {
|
||||
|
@ -153,7 +152,7 @@ class ApiTimelineFriendsAction extends ApiBareAuthAction
|
|||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ class ApiTimelineGroupAction extends ApiPrivateAuthAction
|
|||
break;
|
||||
default:
|
||||
$this->clientError(
|
||||
_('API method not found!'),
|
||||
_('API method not found.'),
|
||||
404,
|
||||
$this->format
|
||||
);
|
||||
|
|
|
@ -153,7 +153,7 @@ class ApiTimelineHomeAction extends ApiBareAuthAction
|
|||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ class ApiTimelineMentionsAction extends ApiBareAuthAction
|
|||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ class ApiTimelinePublicAction extends ApiPrivateAuthAction
|
|||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ class ApiTimelineRetweetedByMeAction extends ApiAuthAction
|
|||
break;
|
||||
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
|
|||
break;
|
||||
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
|
|||
break;
|
||||
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ class ApiTimelineTagAction extends ApiPrivateAuthAction
|
|||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -162,7 +162,7 @@ class ApiTimelineUserAction extends ApiBareAuthAction
|
|||
$this->showJsonTimeline($this->notices);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ class ApiUserShowAction extends ApiPrivateAuthAction
|
|||
}
|
||||
|
||||
if (!in_array($this->format, array('xml', 'json'))) {
|
||||
$this->clientError(_('API method not found!'), $code = 404);
|
||||
$this->clientError(_('API method not found.'), $code = 404);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,14 +70,14 @@ class BlockedfromgroupAction extends GroupDesignAction
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->group = User_group::staticGet('nickname', $nickname);
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ class ConfirmaddressAction extends Action
|
|||
|
||||
function title()
|
||||
{
|
||||
return _('Confirm Address');
|
||||
return _('Confirm address');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -155,7 +155,7 @@ class DeletenoticeAction extends Action
|
|||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. ' .
|
||||
' Try again, please.'));
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
264
actions/editapplication.php
Normal file
264
actions/editapplication.php
Normal file
|
@ -0,0 +1,264 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Edit an OAuth Application
|
||||
*
|
||||
* 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 Applications
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit the details of an OAuth application
|
||||
*
|
||||
* This is the form for editing an application
|
||||
*
|
||||
* @category Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class EditApplicationAction extends OwnerDesignAction
|
||||
{
|
||||
var $msg = null;
|
||||
var $owner = null;
|
||||
var $app = null;
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Edit application');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to edit an application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = (int)$this->arg('id');
|
||||
|
||||
$this->app = Oauth_application::staticGet($id);
|
||||
$this->owner = User::staticGet($this->app->owner);
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur->id != $this->owner->id) {
|
||||
$this->clientError(_('You are not the owner of this application.'), 401);
|
||||
}
|
||||
|
||||
if (!$this->app) {
|
||||
$this->clientError(_('No such application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On GET, show the form. On POST, try to save the app.
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->handlePost($args);
|
||||
} else {
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost($args)
|
||||
{
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
$msg = _('The server was unable to handle that much POST ' .
|
||||
'data (%s bytes) due to its current configuration.');
|
||||
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($this->arg('cancel')) {
|
||||
common_redirect(common_local_url('showapplication',
|
||||
array('id' => $this->app->id)), 303);
|
||||
} elseif ($this->arg('save')) {
|
||||
$this->trySave();
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($msg=null)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$form = new ApplicationEditForm($this, $this->app);
|
||||
$form->show();
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if (!empty($this->msg)) {
|
||||
$this->element('p', 'error', $this->msg);
|
||||
} else {
|
||||
$this->element('p', 'instructions',
|
||||
_('Use this form to edit your application.'));
|
||||
}
|
||||
}
|
||||
|
||||
function trySave()
|
||||
{
|
||||
$name = $this->trimmed('name');
|
||||
$description = $this->trimmed('description');
|
||||
$source_url = $this->trimmed('source_url');
|
||||
$organization = $this->trimmed('organization');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$callback_url = $this->trimmed('callback_url');
|
||||
$type = $this->arg('app_type');
|
||||
$access_type = $this->arg('default_access_type');
|
||||
|
||||
if (empty($name)) {
|
||||
$this->showForm(_('Name is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($name) > 255) {
|
||||
$this->showForm(_('Name is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($description)) {
|
||||
$this->showForm(_('Description is required.'));
|
||||
return;
|
||||
} elseif (Oauth_application::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(
|
||||
_('Description is too long (max %d chars).'),
|
||||
Oauth_application::maxDescription()));
|
||||
return;
|
||||
} elseif (mb_strlen($source_url) > 255) {
|
||||
$this->showForm(_('Source URL is too long.'));
|
||||
return;
|
||||
} elseif ((mb_strlen($source_url) > 0)
|
||||
&& !Validate::uri($source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))))
|
||||
{
|
||||
$this->showForm(_('Source URL is not valid.'));
|
||||
return;
|
||||
} elseif (empty($organization)) {
|
||||
$this->showForm(_('Organization is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($organization) > 255) {
|
||||
$this->showForm(_('Organization is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($homepage)) {
|
||||
$this->showForm(_('Organization homepage is required.'));
|
||||
return;
|
||||
} elseif ((mb_strlen($homepage) > 0)
|
||||
&& !Validate::uri($homepage,
|
||||
array('allowed_schemes' => array('http', 'https'))))
|
||||
{
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} elseif (mb_strlen($callback_url) > 255) {
|
||||
$this->showForm(_('Callback is too long.'));
|
||||
return;
|
||||
} elseif (mb_strlen($callback_url) > 0
|
||||
&& !Validate::uri($source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
))
|
||||
{
|
||||
$this->showForm(_('Callback URL is not valid.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
// Checked in prepare() above
|
||||
|
||||
assert(!is_null($cur));
|
||||
assert(!is_null($this->app));
|
||||
|
||||
$orig = clone($this->app);
|
||||
|
||||
$this->app->name = $name;
|
||||
$this->app->description = $description;
|
||||
$this->app->source_url = $source_url;
|
||||
$this->app->organization = $organization;
|
||||
$this->app->homepage = $homepage;
|
||||
$this->app->callback_url = $callback_url;
|
||||
$this->app->type = $type;
|
||||
|
||||
common_debug("access_type = $access_type");
|
||||
|
||||
if ($access_type == 'r') {
|
||||
$this->app->access_type = 1;
|
||||
} else {
|
||||
$this->app->access_type = 3;
|
||||
}
|
||||
|
||||
$result = $this->app->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($this->app, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Could not update application.'));
|
||||
}
|
||||
|
||||
$this->app->uploadLogo();
|
||||
|
||||
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ class EditgroupAction extends GroupDesignAction
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -93,14 +93,14 @@ class EditgroupAction extends GroupDesignAction
|
|||
}
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!$cur->isAdmin($this->group)) {
|
||||
$this->clientError(_('You must be an admin to edit the group'), 403);
|
||||
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ class EditgroupAction extends GroupDesignAction
|
|||
{
|
||||
$cur = common_current_user();
|
||||
if (!$cur->isAdmin($this->group)) {
|
||||
$this->clientError(_('You must be an admin to edit the group'), 403);
|
||||
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
|||
|
||||
function title()
|
||||
{
|
||||
return _('Email Settings');
|
||||
return _('Email settings');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,7 +118,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
|||
} else {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('email', _('Email Address'),
|
||||
$this->input('email', _('Email address'),
|
||||
($this->arg('email')) ? $this->arg('email') : null,
|
||||
_('Email address, like "UserName@example.org"'));
|
||||
$this->elementEnd('li');
|
||||
|
@ -328,7 +328,7 @@ class EmailsettingsAction extends AccountSettingsAction
|
|||
return;
|
||||
}
|
||||
if (!Validate::email($email, common_config('email', 'check_domain'))) {
|
||||
$this->showForm(_('Not a valid email address'));
|
||||
$this->showForm(_('Not a valid email address.'));
|
||||
return;
|
||||
} else if ($user->email == $email) {
|
||||
$this->showForm(_('That is already your email address.'));
|
||||
|
|
|
@ -71,7 +71,7 @@ class GroupbyidAction extends Action
|
|||
$id = $this->arg('id');
|
||||
|
||||
if (!$id) {
|
||||
$this->clientError(_('No ID'));
|
||||
$this->clientError(_('No ID.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ class GroupbyidAction extends Action
|
|||
$this->group = User_group::staticGet('id', $id);
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ class GroupDesignSettingsAction extends DesignSettingsAction
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -94,14 +94,14 @@ class GroupDesignSettingsAction extends DesignSettingsAction
|
|||
}
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!$cur->isAdmin($this->group)) {
|
||||
$this->clientError(_('You must be an admin to edit the group'), 403);
|
||||
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,7 @@ class GroupDesignSettingsAction extends DesignSettingsAction
|
|||
|
||||
if (empty($id)) {
|
||||
common_log_db_error($id, 'INSERT', __FILE__);
|
||||
$this->showForm(_('Unable to save your design settings!'));
|
||||
$this->showForm(_('Unable to save your design settings.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ class GroupDesignSettingsAction extends DesignSettingsAction
|
|||
|
||||
if (empty($result)) {
|
||||
common_log_db_error($original, 'UPDATE', __FILE__);
|
||||
$this->showForm(_('Unable to save your design settings!'));
|
||||
$this->showForm(_('Unable to save your design settings.'));
|
||||
$this->group->query('ROLLBACK');
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ class GrouplogoAction extends GroupDesignAction
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -96,14 +96,14 @@ class GrouplogoAction extends GroupDesignAction
|
|||
}
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!$cur->isAdmin($this->group)) {
|
||||
$this->clientError(_('You must be an admin to edit the group'), 403);
|
||||
$this->clientError(_('You must be an admin to edit the group.'), 403);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,7 @@ class GrouplogoAction extends GroupDesignAction
|
|||
|
||||
if (!$profile) {
|
||||
common_log_db_error($user, 'SELECT', __FILE__);
|
||||
$this->serverError(_('User without matching profile'));
|
||||
$this->serverError(_('User without matching profile.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,14 +73,14 @@ class GroupmembersAction extends GroupDesignAction
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->group = User_group::staticGet('nickname', $nickname);
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||
|
||||
function title()
|
||||
{
|
||||
return _('IM Settings');
|
||||
return _('IM settings');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,7 +121,7 @@ class ImsettingsAction extends ConnectSettingsAction
|
|||
} else {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('jabber', _('IM Address'),
|
||||
$this->input('jabber', _('IM address'),
|
||||
($this->arg('jabber')) ? $this->arg('jabber') : null,
|
||||
sprintf(_('Jabber or GTalk address, '.
|
||||
'like "UserName@example.org". '.
|
||||
|
|
|
@ -73,21 +73,21 @@ class JoingroupAction extends Action
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->group = User_group::staticGet('nickname', $nickname);
|
||||
|
||||
if (!$this->group) {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur->isMember($this->group)) {
|
||||
$this->clientError(_('You are already a member of that group'), 403);
|
||||
$this->clientError(_('You are already a member of that group.'), 403);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -115,17 +115,13 @@ class JoingroupAction extends Action
|
|||
|
||||
$cur = common_current_user();
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $this->group->id;
|
||||
$member->profile_id = $cur->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 %1$s to group %2$s'),
|
||||
try {
|
||||
if (Event::handle('StartJoinGroup', array($this->group, $cur))) {
|
||||
Group_member::join($this->group->id, $cur->id);
|
||||
Event::handle('EndJoinGroup', array($this->group, $cur));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->serverError(sprintf(_('Could not join user %1$s to group %2$s.'),
|
||||
$cur->nickname, $this->group->nickname));
|
||||
}
|
||||
|
||||
|
|
|
@ -110,22 +110,15 @@ class LeavegroupAction extends Action
|
|||
|
||||
$cur = common_current_user();
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $this->group->id;
|
||||
$member->profile_id = $cur->id;
|
||||
|
||||
if (!$member->find(true)) {
|
||||
$this->serverError(_('Could not find membership record.'));
|
||||
return;
|
||||
try {
|
||||
if (Event::handle('StartLeaveGroup', array($this->group, $cur))) {
|
||||
Group_member::leave($this->group->id, $cur->id);
|
||||
Event::handle('EndLeaveGroup', array($this->group, $cur));
|
||||
}
|
||||
|
||||
$result = $member->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'DELETE', __FILE__);
|
||||
} catch (Exception $e) {
|
||||
$this->serverError(sprintf(_('Could not remove user %1$s from group %2$s.'),
|
||||
$cur->nickname, $this->group->nickname));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
|
|
|
@ -76,15 +76,10 @@ class LoginAction extends Action
|
|||
{
|
||||
parent::handle($args);
|
||||
|
||||
$disabled = common_config('logincommand','disabled');
|
||||
$disabled = isset($disabled) && $disabled;
|
||||
|
||||
if (common_is_real_login()) {
|
||||
$this->clientError(_('Already logged in.'));
|
||||
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->checkLogin();
|
||||
} else if (!$disabled && isset($args['user_id']) && isset($args['token'])){
|
||||
$this->checkLogin($args['user_id'],$args['token']);
|
||||
} else {
|
||||
common_ensure_session();
|
||||
$this->showForm();
|
||||
|
@ -103,35 +98,20 @@ class LoginAction extends Action
|
|||
|
||||
function checkLogin($user_id=null, $token=null)
|
||||
{
|
||||
if(isset($token) && isset($user_id)){
|
||||
//Token based login (from the LoginCommand)
|
||||
$login_token = Login_token::staticGet('user_id',$user_id);
|
||||
if($login_token && $login_token->token == $token){
|
||||
if($login_token->modified > time()+2*60){
|
||||
//token has expired
|
||||
//delete the token as it is useless
|
||||
$login_token->delete();
|
||||
$this->showForm(_('Invalid or expired token.'));
|
||||
return;
|
||||
}else{
|
||||
//delete the token so it cannot be reused
|
||||
$login_token->delete();
|
||||
//it's a valid token - let them log in
|
||||
$user = User::staticGet('id', $user_id);
|
||||
//$user = User::staticGet('nickname', "candrews");
|
||||
}
|
||||
}else{
|
||||
$this->showForm(_('Invalid or expired token.'));
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
// Regular form submission login
|
||||
|
||||
// XXX: login throttle
|
||||
|
||||
// CSRF protection - token set in NoticeForm
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$st = common_session_token();
|
||||
if (empty($token)) {
|
||||
common_log(LOG_WARNING, 'No token provided by client.');
|
||||
} else if (empty($st)) {
|
||||
common_log(LOG_WARNING, 'No session token stored.');
|
||||
} else {
|
||||
common_log(LOG_WARNING, 'Token = ' . $token . ' and session token = ' . $st);
|
||||
}
|
||||
|
||||
$this->clientError(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
|
@ -141,7 +121,6 @@ class LoginAction extends Action
|
|||
$password = $this->arg('password');
|
||||
|
||||
$user = common_check_user($nickname, $password);
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
$this->showForm(_('Incorrect username or password.'));
|
||||
|
@ -165,6 +144,7 @@ class LoginAction extends Action
|
|||
if ($url) {
|
||||
// We don't have to return to it again
|
||||
common_set_returnto(null);
|
||||
$url = common_inject_session($url);
|
||||
} else {
|
||||
$url = common_local_url('all',
|
||||
array('nickname' =>
|
||||
|
|
|
@ -129,7 +129,7 @@ class MakeadminAction extends Action
|
|||
'profile_id' => $this->profile->id));
|
||||
|
||||
if (empty($member)) {
|
||||
$this->serverError(_('Can\'t get membership record for %1$s in group %2$s'),
|
||||
$this->serverError(_('Can\'t get membership record for %1$s in group %2$s.'),
|
||||
$this->profile->getBestName(),
|
||||
$this->group->getBestName());
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ class MakeadminAction extends Action
|
|||
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'UPDATE', __FILE__);
|
||||
$this->serverError(_('Can\'t make %1$s an admin for group %2$s'),
|
||||
$this->serverError(_('Can\'t make %1$s an admin for group %2$s.'),
|
||||
$this->profile->getBestName(),
|
||||
$this->group->getBestName());
|
||||
}
|
||||
|
|
277
actions/newapplication.php
Normal file
277
actions/newapplication.php
Normal file
|
@ -0,0 +1,277 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Register a new OAuth Application
|
||||
*
|
||||
* 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 Applications
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new application
|
||||
*
|
||||
* This is the form for adding a new application
|
||||
*
|
||||
* @category Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class NewApplicationAction extends OwnerDesignAction
|
||||
{
|
||||
var $msg;
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('New application');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to run
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to register an application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* On GET, show the form. On POST, try to save the app.
|
||||
*
|
||||
* @param array $args unused
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
$this->handlePost($args);
|
||||
} else {
|
||||
$this->showForm();
|
||||
}
|
||||
}
|
||||
|
||||
function handlePost($args)
|
||||
{
|
||||
// Workaround for PHP returning empty $_POST and $_FILES when POST
|
||||
// length > post_max_size in php.ini
|
||||
|
||||
if (empty($_FILES)
|
||||
&& empty($_POST)
|
||||
&& ($_SERVER['CONTENT_LENGTH'] > 0)
|
||||
) {
|
||||
$msg = _('The server was unable to handle that much POST ' .
|
||||
'data (%s bytes) due to its current configuration.');
|
||||
$this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
|
||||
return;
|
||||
}
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($this->arg('cancel')) {
|
||||
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||
} elseif ($this->arg('save')) {
|
||||
$this->trySave();
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'));
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($msg=null)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$form = new ApplicationEditForm($this);
|
||||
$form->show();
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->msg) {
|
||||
$this->element('p', 'error', $this->msg);
|
||||
} else {
|
||||
$this->element('p', 'instructions',
|
||||
_('Use this form to register a new application.'));
|
||||
}
|
||||
}
|
||||
|
||||
function trySave()
|
||||
{
|
||||
$name = $this->trimmed('name');
|
||||
$description = $this->trimmed('description');
|
||||
$source_url = $this->trimmed('source_url');
|
||||
$organization = $this->trimmed('organization');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$callback_url = $this->trimmed('callback_url');
|
||||
$type = $this->arg('app_type');
|
||||
$access_type = $this->arg('default_access_type');
|
||||
|
||||
if (empty($name)) {
|
||||
$this->showForm(_('Name is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($name) > 255) {
|
||||
$this->showForm(_('Name is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($description)) {
|
||||
$this->showForm(_('Description is required.'));
|
||||
return;
|
||||
} elseif (Oauth_application::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(
|
||||
_('Description is too long (max %d chars).'),
|
||||
Oauth_application::maxDescription()));
|
||||
return;
|
||||
} elseif (empty($source_url)) {
|
||||
$this->showForm(_('Source URL is required.'));
|
||||
return;
|
||||
} elseif ((strlen($source_url) > 0)
|
||||
&& !Validate::uri(
|
||||
$source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
)
|
||||
)
|
||||
{
|
||||
$this->showForm(_('Source URL is not valid.'));
|
||||
return;
|
||||
} elseif (empty($organization)) {
|
||||
$this->showForm(_('Organization is required.'));
|
||||
return;
|
||||
} elseif (mb_strlen($organization) > 255) {
|
||||
$this->showForm(_('Organization is too long (max 255 chars).'));
|
||||
return;
|
||||
} elseif (empty($homepage)) {
|
||||
$this->showForm(_('Organization homepage is required.'));
|
||||
return;
|
||||
} elseif ((strlen($homepage) > 0)
|
||||
&& !Validate::uri(
|
||||
$homepage,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
)
|
||||
)
|
||||
{
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} elseif (mb_strlen($callback_url) > 255) {
|
||||
$this->showForm(_('Callback is too long.'));
|
||||
return;
|
||||
} elseif (strlen($callback_url) > 0
|
||||
&& !Validate::uri(
|
||||
$source_url,
|
||||
array('allowed_schemes' => array('http', 'https'))
|
||||
)
|
||||
)
|
||||
{
|
||||
$this->showForm(_('Callback URL is not valid.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
// Checked in prepare() above
|
||||
|
||||
assert(!is_null($cur));
|
||||
|
||||
$app = new Oauth_application();
|
||||
|
||||
$app->query('BEGIN');
|
||||
|
||||
$app->name = $name;
|
||||
$app->owner = $cur->id;
|
||||
$app->description = $description;
|
||||
$app->source_url = $source_url;
|
||||
$app->organization = $organization;
|
||||
$app->homepage = $homepage;
|
||||
$app->callback_url = $callback_url;
|
||||
$app->type = $type;
|
||||
|
||||
// Yeah, I dunno why I chose bit flags. I guess so I could
|
||||
// copy this value directly to Oauth_application_user
|
||||
// access_type which I think does need bit flags -- Z
|
||||
|
||||
if ($access_type == 'r') {
|
||||
$app->setAccessFlags(true, false);
|
||||
} else {
|
||||
$app->setAccessFlags(true, true);
|
||||
}
|
||||
|
||||
$app->created = common_sql_now();
|
||||
|
||||
// generate consumer key and secret
|
||||
|
||||
$consumer = Consumer::generateNew();
|
||||
|
||||
$result = $consumer->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($consumer, 'INSERT', __FILE__);
|
||||
$this->serverError(_('Could not create application.'));
|
||||
}
|
||||
|
||||
$app->consumer_key = $consumer->consumer_key;
|
||||
|
||||
$this->app_id = $app->insert();
|
||||
|
||||
if (!$this->app_id) {
|
||||
common_log_db_error($app, 'INSERT', __FILE__);
|
||||
$this->serverError(_('Could not create application.'));
|
||||
$app->query('ROLLBACK');
|
||||
}
|
||||
|
||||
$app->uploadLogo();
|
||||
|
||||
$app->query('COMMIT');
|
||||
|
||||
common_redirect(common_local_url('oauthappssettings'), 303);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -182,7 +182,7 @@ class NewmessageAction extends Action
|
|||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$this->element('p', array('id' => 'command_result'),
|
||||
sprintf(_('Direct message to %s sent'),
|
||||
sprintf(_('Direct message to %s sent.'),
|
||||
$this->other->nickname));
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
|
|
166
actions/oauthappssettings.php
Normal file
166
actions/oauthappssettings.php
Normal file
|
@ -0,0 +1,166 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List the OAuth applications that a user has registered with this instance
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Settings
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 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/settingsaction.php';
|
||||
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
|
||||
/**
|
||||
* Show a user's registered OAuth applications
|
||||
*
|
||||
* @category Settings
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see SettingsAction
|
||||
*/
|
||||
|
||||
class OauthappssettingsAction extends SettingsAction
|
||||
{
|
||||
var $page = 0;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to list your applications.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('OAuth applications');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for use
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Applications you have registered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Content area of the page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$offset = ($this->page - 1) * APPS_PER_PAGE;
|
||||
$limit = APPS_PER_PAGE + 1;
|
||||
|
||||
$application = new Oauth_application();
|
||||
$application->owner = $user->id;
|
||||
$application->limit($offset, $limit);
|
||||
$application->orderBy('created DESC');
|
||||
$application->find();
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
if ($application) {
|
||||
$al = new ApplicationList($application, $user, $this);
|
||||
$cnt = $al->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementStart('p', array('id' => 'application_register'));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('newapplication'),
|
||||
'class' => 'more'
|
||||
),
|
||||
'Register a new application');
|
||||
$this->elementEnd('p');
|
||||
|
||||
$this->pagination(
|
||||
$this->page > 1,
|
||||
$cnt > APPS_PER_PAGE,
|
||||
$this->page,
|
||||
'oauthappssettings'
|
||||
);
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('You have not registered any applications yet.'));
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posts to this form
|
||||
*
|
||||
* Based on the button that was pressed, muxes out to other functions
|
||||
* to do the actual task requested.
|
||||
*
|
||||
* All sub-functions reload the form with a message -- success or failure.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
212
actions/oauthconnectionssettings.php
Normal file
212
actions/oauthconnectionssettings.php
Normal file
|
@ -0,0 +1,212 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* List a user's OAuth connected applications
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* LICENCE: This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @category Settings
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 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/connectsettingsaction.php';
|
||||
require_once INSTALLDIR . '/lib/applicationlist.php';
|
||||
|
||||
/**
|
||||
* Show connected OAuth applications
|
||||
*
|
||||
* @category Settings
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see SettingsAction
|
||||
*/
|
||||
|
||||
class OauthconnectionssettingsAction extends ConnectSettingsAction
|
||||
{
|
||||
|
||||
var $page = null;
|
||||
var $id = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->id = (int)$this->arg('id');
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page') + 0) : 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Connected applications');
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for use
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('You have allowed the following applications to access you account.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Content area of the page
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$offset = ($this->page - 1) * APPS_PER_PAGE;
|
||||
$limit = APPS_PER_PAGE + 1;
|
||||
|
||||
$application = $profile->getApplications($offset, $limit);
|
||||
|
||||
$cnt == 0;
|
||||
|
||||
if (!empty($application)) {
|
||||
$al = new ApplicationList($application, $user, $this, true);
|
||||
$cnt = $al->show();
|
||||
}
|
||||
|
||||
if ($cnt == 0) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > APPS_PER_PAGE,
|
||||
$this->page, 'connectionssettings',
|
||||
array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle posts to this form
|
||||
*
|
||||
* Based on the button that was pressed, muxes out to other functions
|
||||
* to do the actual task requested.
|
||||
*
|
||||
* All sub-functions reload the form with a message -- success or failure.
|
||||
*
|
||||
* @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('revoke')) {
|
||||
$this->revokeAccess($this->id);
|
||||
|
||||
// XXX: Show some indicator to the user of what's been done.
|
||||
|
||||
$this->showPage();
|
||||
} else {
|
||||
$this->clientError(_('Unexpected form submission.'), 401);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function revokeAccess($appId)
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
$app = Oauth_application::staticGet('id', $appId);
|
||||
|
||||
if (empty($app)) {
|
||||
$this->clientError(_('No such application.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$appUser = Oauth_application_user::getByKeys($cur, $app);
|
||||
|
||||
if (empty($appUser)) {
|
||||
$this->clientError(_('You are not a user of that application.'), 401);
|
||||
return false;
|
||||
}
|
||||
|
||||
$orig = clone($appUser);
|
||||
$appUser->access_type = 0; // No access
|
||||
$result = $appUser->update();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($orig, 'UPDATE', __FILE__);
|
||||
$this->clientError(_('Unable to revoke access for app: ' . $app->id));
|
||||
return false;
|
||||
}
|
||||
|
||||
$msg = 'User %s (id: %d) revoked access to app %s (id: %d)';
|
||||
common_log(LOG_INFO, sprintf($msg, $cur->nickname,
|
||||
$cur->id, $app->name, $app->id));
|
||||
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('You have not authorized any applications to use your account.'));
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
$this->element('h2', null, 'Developers');
|
||||
$this->elementStart('p');
|
||||
$this->raw(_('Developers can edit the registration settings for their applications '));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('oauthappssettings')),
|
||||
'here.');
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
}
|
|
@ -57,7 +57,7 @@ class OthersettingsAction extends AccountSettingsAction
|
|||
|
||||
function title()
|
||||
{
|
||||
return _('Other Settings');
|
||||
return _('Other settings');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
145
actions/otp.php
Normal file
145
actions/otp.php
Normal file
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Allow one-time password login
|
||||
*
|
||||
* 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 Login
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow one-time password login
|
||||
*
|
||||
* This action will automatically log in the user identified by the user_id
|
||||
* parameter. A login_token record must be constructed beforehand, typically
|
||||
* by code where the user is already authenticated.
|
||||
*
|
||||
* @category Login
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class OtpAction extends Action
|
||||
{
|
||||
var $user;
|
||||
var $token;
|
||||
var $rememberme;
|
||||
var $returnto;
|
||||
var $lt;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
if (common_is_real_login()) {
|
||||
$this->clientError(_('Already logged in.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->trimmed('user_id');
|
||||
|
||||
if (empty($id)) {
|
||||
$this->clientError(_('No user ID specified.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->user = User::staticGet('id', $id);
|
||||
|
||||
if (empty($this->user)) {
|
||||
$this->clientError(_('No such user.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->token = $this->trimmed('token');
|
||||
|
||||
if (empty($this->token)) {
|
||||
$this->clientError(_('No login token specified.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->lt = Login_token::staticGet('user_id', $id);
|
||||
|
||||
if (empty($this->lt)) {
|
||||
$this->clientError(_('No login token requested.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->lt->token != $this->token) {
|
||||
$this->clientError(_('Invalid login token specified.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->lt->modified > time() + Login_token::TIMEOUT) {
|
||||
//token has expired
|
||||
//delete the token as it is useless
|
||||
$this->lt->delete();
|
||||
$this->lt = null;
|
||||
$this->clientError(_('Login token expired.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->rememberme = $this->boolean('rememberme');
|
||||
$this->returnto = $this->trimmed('returnto');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
// success!
|
||||
if (!common_set_user($this->user)) {
|
||||
$this->serverError(_('Error setting user. You are probably not authorized.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// We're now logged in; disable the lt
|
||||
|
||||
$this->lt->delete();
|
||||
$this->lt = null;
|
||||
|
||||
if ($this->rememberme) {
|
||||
common_rememberme($this->user);
|
||||
}
|
||||
|
||||
if (!empty($this->returnto)) {
|
||||
$url = $this->returnto;
|
||||
// We don't have to return to it again
|
||||
common_set_returnto(null);
|
||||
} else {
|
||||
$url = common_local_url('all',
|
||||
array('nickname' =>
|
||||
$this->user->nickname));
|
||||
}
|
||||
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
}
|
|
@ -305,7 +305,7 @@ class PathsAdminPanelForm extends AdminForm
|
|||
$this->unli();
|
||||
|
||||
$this->li();
|
||||
$this->input('sslserver', _('SSL Server'),
|
||||
$this->input('sslserver', _('SSL server'),
|
||||
_('Server to direct SSL requests to'), 'site');
|
||||
$this->unli();
|
||||
$this->out->elementEnd('ul');
|
||||
|
|
|
@ -259,6 +259,7 @@ class RegisterAction extends Action
|
|||
|
||||
// Re-init language env in case it changed (not yet, but soon)
|
||||
common_init_language();
|
||||
|
||||
$this->showSuccess();
|
||||
} else {
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
|
|
327
actions/showapplication.php
Normal file
327
actions/showapplication.php
Normal file
|
@ -0,0 +1,327 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show an OAuth application
|
||||
*
|
||||
* 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 Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an OAuth application
|
||||
*
|
||||
* @category Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ShowApplicationAction extends OwnerDesignAction
|
||||
{
|
||||
/**
|
||||
* Application to show
|
||||
*/
|
||||
|
||||
var $application = null;
|
||||
|
||||
/**
|
||||
* User who owns the app
|
||||
*/
|
||||
|
||||
var $owner = null;
|
||||
|
||||
var $msg = null;
|
||||
|
||||
var $success = null;
|
||||
|
||||
/**
|
||||
* Load attributes based on database arguments
|
||||
*
|
||||
* Loads all the DB stuff
|
||||
*
|
||||
* @param array $args $_REQUEST array
|
||||
*
|
||||
* @return success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = (int)$this->arg('id');
|
||||
|
||||
$this->application = Oauth_application::staticGet($id);
|
||||
$this->owner = User::staticGet($this->application->owner);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('You must be logged in to view an application.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($this->application)) {
|
||||
$this->clientError(_('No such application.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
if ($cur->id != $this->owner->id) {
|
||||
$this->clientError(_('You are not the owner of this application.'), 401);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the request
|
||||
*
|
||||
* Shows info about the app
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->clientError(_('There was a problem with your session token.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->arg('reset')) {
|
||||
$this->resetKey();
|
||||
}
|
||||
} else {
|
||||
$this->showPage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
if (!empty($this->application->name)) {
|
||||
return 'Application: ' . $this->application->name;
|
||||
}
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if (!empty($this->msg)) {
|
||||
$this->element('div', ($this->success) ? 'success' : 'error', $this->msg);
|
||||
}
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
$consumer = $this->application->getConsumer();
|
||||
|
||||
$this->elementStart('div', 'entity_profile vcard');
|
||||
$this->element('h2', null, _('Application profile'));
|
||||
$this->elementStart('dl', 'entity_depiction');
|
||||
$this->element('dt', null, _('Icon'));
|
||||
$this->elementStart('dd');
|
||||
if (!empty($this->application->icon)) {
|
||||
$this->element('img', array('src' => $this->application->icon,
|
||||
'class' => 'photo logo'));
|
||||
}
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_fn');
|
||||
$this->element('dt', null, _('Name'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => $this->application->source_url,
|
||||
'class' => 'url fn'),
|
||||
$this->application->name);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_org');
|
||||
$this->element('dt', null, _('Organization'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => $this->application->homepage,
|
||||
'class' => 'url'),
|
||||
$this->application->organization);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_note');
|
||||
$this->element('dt', null, _('Description'));
|
||||
$this->element('dd', 'note', $this->application->description);
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_statistics');
|
||||
$this->element('dt', null, _('Statistics'));
|
||||
$this->elementStart('dd');
|
||||
$defaultAccess = ($this->application->access_type & Oauth_application::$writeAccess)
|
||||
? 'read-write' : 'read-only';
|
||||
$profile = Profile::staticGet($this->application->owner);
|
||||
|
||||
$appUsers = new Oauth_application_user();
|
||||
$appUsers->application_id = $this->application->id;
|
||||
$userCnt = $appUsers->count();
|
||||
|
||||
$this->raw(sprintf(
|
||||
_('created by %1$s - %2$s access by default - %3$d users'),
|
||||
$profile->getBestName(),
|
||||
$defaultAccess,
|
||||
$userCnt
|
||||
));
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'entity_actions');
|
||||
$this->element('h2', null, _('Application actions'));
|
||||
$this->elementStart('ul');
|
||||
$this->elementStart('li', 'entity_edit');
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('editapplication',
|
||||
array('id' => $this->application->id))),
|
||||
'Edit');
|
||||
$this->elementEnd('li');
|
||||
|
||||
$this->elementStart('li', 'entity_reset_keysecret');
|
||||
$this->elementStart('form', array(
|
||||
'id' => 'forma_reset_key',
|
||||
'class' => 'form_reset_key',
|
||||
'method' => 'POST',
|
||||
'action' => common_local_url('showapplication',
|
||||
array('id' => $this->application->id))));
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->submit('reset', _('Reset key & secret'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'entity_data');
|
||||
$this->element('h2', null, _('Application info'));
|
||||
$this->elementStart('dl', 'entity_consumer_key');
|
||||
$this->element('dt', null, _('Consumer key'));
|
||||
$this->element('dd', null, $consumer->consumer_key);
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_consumer_secret');
|
||||
$this->element('dt', null, _('Consumer secret'));
|
||||
$this->element('dd', null, $consumer->consumer_secret);
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_request_token_url');
|
||||
$this->element('dt', null, _('Request token URL'));
|
||||
$this->element('dd', null, common_local_url('apioauthrequesttoken'));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_access_token_url');
|
||||
$this->element('dt', null, _('Access token URL'));
|
||||
$this->element('dd', null, common_local_url('apioauthaccesstoken'));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_authorize_url');
|
||||
$this->element('dt', null, _('Authorize URL'));
|
||||
$this->element('dd', null, common_local_url('apioauthauthorize'));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->element('p', 'note',
|
||||
_('Note: We support HMAC-SHA1 signatures. We do not support the plaintext signature method.'));
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('p', array('id' => 'application_action'));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('oauthappssettings'),
|
||||
'class' => 'more'),
|
||||
'View your applications');
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
function resetKey()
|
||||
{
|
||||
$this->application->query('BEGIN');
|
||||
|
||||
$consumer = $this->application->getConsumer();
|
||||
$result = $consumer->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($consumer, 'DELETE', __FILE__);
|
||||
$this->success = false;
|
||||
$this->msg = ('Unable to reset consumer key and secret.');
|
||||
$this->showPage();
|
||||
return;
|
||||
}
|
||||
|
||||
$consumer = Consumer::generateNew();
|
||||
|
||||
$result = $consumer->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($consumer, 'INSERT', __FILE__);
|
||||
$this->application->query('ROLLBACK');
|
||||
$this->success = false;
|
||||
$this->msg = ('Unable to reset consumer key and secret.');
|
||||
$this->showPage();
|
||||
return;
|
||||
}
|
||||
|
||||
$orig = clone($this->application);
|
||||
$this->application->consumer_key = $consumer->consumer_key;
|
||||
$result = $this->application->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($application, 'UPDATE', __FILE__);
|
||||
$this->application->query('ROLLBACK');
|
||||
$this->success = false;
|
||||
$this->msg = ('Unable to reset consumer key and secret.');
|
||||
$this->showPage();
|
||||
return;
|
||||
}
|
||||
|
||||
$this->application->query('COMMIT');
|
||||
|
||||
$this->success = true;
|
||||
$this->msg = ('Consumer key and secret reset.');
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
}
|
|
@ -118,7 +118,7 @@ class ShowgroupAction extends GroupDesignAction
|
|||
}
|
||||
|
||||
if (!$nickname) {
|
||||
$this->clientError(_('No nickname'), 404);
|
||||
$this->clientError(_('No nickname.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ class ShowgroupAction extends GroupDesignAction
|
|||
common_redirect(common_local_url('groupbyid', $args), 301);
|
||||
return false;
|
||||
} else {
|
||||
$this->clientError(_('No such group'), 404);
|
||||
$this->clientError(_('No such group.'), 404);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,10 +151,10 @@ class SiteadminpanelAction extends AdminPanelAction
|
|||
$values['site']['email'] = common_canonical_email($values['site']['email']);
|
||||
|
||||
if (empty($values['site']['email'])) {
|
||||
$this->clientError(_('You must have a valid contact email address'));
|
||||
$this->clientError(_('You must have a valid contact email address.'));
|
||||
}
|
||||
if (!Validate::email($values['site']['email'], common_config('email', 'check_domain'))) {
|
||||
$this->clientError(_('Not a valid email address'));
|
||||
$this->clientError(_('Not a valid email address.'));
|
||||
}
|
||||
|
||||
// Validate timezone
|
||||
|
@ -169,7 +169,7 @@ class SiteadminpanelAction extends AdminPanelAction
|
|||
|
||||
if (!is_null($values['site']['language']) &&
|
||||
!in_array($values['site']['language'], array_keys(get_nice_language_list()))) {
|
||||
$this->clientError(sprintf(_('Unknown language "%s"'), $values['site']['language']));
|
||||
$this->clientError(sprintf(_('Unknown language "%s".'), $values['site']['language']));
|
||||
}
|
||||
|
||||
// Validate report URL
|
||||
|
|
|
@ -55,7 +55,7 @@ class SmssettingsAction extends ConnectSettingsAction
|
|||
|
||||
function title()
|
||||
{
|
||||
return _('SMS Settings');
|
||||
return _('SMS settings');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,7 +135,7 @@ class SmssettingsAction extends ConnectSettingsAction
|
|||
} else {
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('sms', _('SMS Phone number'),
|
||||
$this->input('sms', _('SMS phone number'),
|
||||
($this->arg('sms')) ? $this->arg('sms') : null,
|
||||
_('Phone number, no punctuation or spaces, '.
|
||||
'with area code'));
|
||||
|
|
|
@ -58,7 +58,7 @@ class SubscribeAction extends Action
|
|||
|
||||
$result = subs_subscribe_to($user, $other);
|
||||
|
||||
if($result != true) {
|
||||
if (is_string($result)) {
|
||||
$this->clientError($result);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -163,8 +163,8 @@ class TagotherAction extends Action
|
|||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token.'.
|
||||
' Try again, please.'));
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -81,13 +81,13 @@ class UnsubscribeAction extends Action
|
|||
$other = Profile::staticGet('id', $other_id);
|
||||
|
||||
if (!$other) {
|
||||
$this->clientError(_('No profile with that id.'));
|
||||
$this->clientError(_('No profile with that ID.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$result = subs_unsubscribe_to($user, $other);
|
||||
|
||||
if ($result != true) {
|
||||
if (is_string($result)) {
|
||||
$this->clientError($result);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -207,7 +207,7 @@ class UserDesignSettingsAction extends DesignSettingsAction
|
|||
|
||||
if (empty($id)) {
|
||||
common_log_db_error($id, 'INSERT', __FILE__);
|
||||
$this->showForm(_('Unable to save your design settings!'));
|
||||
$this->showForm(_('Unable to save your design settings.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ class UserDesignSettingsAction extends DesignSettingsAction
|
|||
|
||||
if (empty($result)) {
|
||||
common_log_db_error($original, 'UPDATE', __FILE__);
|
||||
$this->showForm(_('Unable to save your design settings!'));
|
||||
$this->showForm(_('Unable to save your design settings.'));
|
||||
$user->query('ROLLBACK');
|
||||
return;
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ class UserDesignSettingsAction extends DesignSettingsAction
|
|||
|
||||
if (empty($id)) {
|
||||
common_log_db_error($id, 'INSERT', __FILE__);
|
||||
$this->showForm(_('Unable to save your design settings!'));
|
||||
$this->showForm(_('Unable to save your design settings.'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -270,7 +270,7 @@ class UserDesignSettingsAction extends DesignSettingsAction
|
|||
|
||||
if (empty($result)) {
|
||||
common_log_db_error($original, 'UPDATE', __FILE__);
|
||||
$this->showForm(_('Unable to save your design settings!'));
|
||||
$this->showForm(_('Unable to save your design settings.'));
|
||||
$user->query('ROLLBACK');
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -266,5 +266,6 @@ class VersionAction extends Action
|
|||
'Craig Andrews',
|
||||
'mEDI',
|
||||
'Brett Taylor',
|
||||
'Brigitte Schuster');
|
||||
'Brigitte Schuster',
|
||||
'Brion Vibber');
|
||||
}
|
||||
|
|
|
@ -11,9 +11,10 @@ class Consumer extends Memcached_DataObject
|
|||
|
||||
public $__table = 'consumer'; // table name
|
||||
public $consumer_key; // varchar(255) primary_key not_null
|
||||
public $consumer_secret; // varchar(255) not_null
|
||||
public $seed; // char(32) not_null
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=null)
|
||||
|
@ -21,4 +22,18 @@ class Consumer extends Memcached_DataObject
|
|||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
static function generateNew()
|
||||
{
|
||||
$cons = new Consumer();
|
||||
$rand = common_good_rand(16);
|
||||
|
||||
$cons->seed = $rand;
|
||||
$cons->consumer_key = md5(time() + $rand);
|
||||
$cons->consumer_secret = md5(md5(time() + time() + $rand));
|
||||
$cons->created = common_sql_now();
|
||||
|
||||
return $cons;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -80,7 +80,14 @@ class File extends Memcached_DataObject
|
|||
if (isset($redir_data['type'])
|
||||
&& (('text/html' === substr($redir_data['type'], 0, 9) || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))
|
||||
&& ($oembed_data = File_oembed::_getOembed($given_url))) {
|
||||
|
||||
$fo = File_oembed::staticGet('file_id', $file_id);
|
||||
|
||||
if (empty($fo)) {
|
||||
File_oembed::saveNew($oembed_data, $file_id);
|
||||
} else {
|
||||
common_log(LOG_WARNING, "Strangely, a File_oembed object exists for new file $file_id", __FILE__);
|
||||
}
|
||||
}
|
||||
return $x;
|
||||
}
|
||||
|
|
|
@ -115,8 +115,14 @@ class File_oembed extends Memcached_DataObject
|
|||
}
|
||||
$file_oembed->insert();
|
||||
if (!empty($data->thumbnail_url)) {
|
||||
$ft = File_thumbnail::staticGet('file_id', $file_id);
|
||||
if (!empty($ft)) {
|
||||
common_log(LOG_WARNING, "Strangely, a File_thumbnail object exists for new file $file_id",
|
||||
__FILE__);
|
||||
} else {
|
||||
File_thumbnail::saveNew($data, $file_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,4 +25,41 @@ class Group_member extends Memcached_DataObject
|
|||
{
|
||||
return Memcached_DataObject::pkeyGet('Group_member', $kv);
|
||||
}
|
||||
|
||||
static function join($group_id, $profile_id)
|
||||
{
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $group_id;
|
||||
$member->profile_id = $profile_id;
|
||||
$member->created = common_sql_now();
|
||||
|
||||
$result = $member->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'INSERT', __FILE__);
|
||||
throw new Exception(_("Group join failed."));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static function leave($group_id, $profile_id)
|
||||
{
|
||||
$member = Group_member::pkeyGet(array('group_id' => $group_id,
|
||||
'profile_id' => $profile_id));
|
||||
|
||||
if (empty($member)) {
|
||||
throw new Exception(_("Not part of group."));
|
||||
}
|
||||
|
||||
$result = $member->delete();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'INSERT', __FILE__);
|
||||
throw new Exception(_("Group leave failed."));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
180
classes/Inbox.php
Normal file
180
classes/Inbox.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Data class for user location preferences
|
||||
*
|
||||
* 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 Data
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@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/
|
||||
*/
|
||||
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Inbox extends Memcached_DataObject
|
||||
{
|
||||
const BOXCAR = 128;
|
||||
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'inbox'; // table name
|
||||
public $user_id; // int(4) primary_key not_null
|
||||
public $notice_ids; // blob
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Inbox',$k,$v); }
|
||||
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
function sequenceKey()
|
||||
{
|
||||
return array(false, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new inbox from existing Notice_inbox stuff
|
||||
*/
|
||||
|
||||
static function initialize($user_id)
|
||||
{
|
||||
$inbox = Inbox::fromNoticeInbox($user_id);
|
||||
|
||||
unset($inbox->fake);
|
||||
|
||||
$result = $inbox->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($inbox, 'INSERT', __FILE__);
|
||||
return null;
|
||||
}
|
||||
|
||||
return $inbox;
|
||||
}
|
||||
|
||||
static function fromNoticeInbox($user_id)
|
||||
{
|
||||
$ids = array();
|
||||
|
||||
$ni = new Notice_inbox();
|
||||
|
||||
$ni->user_id = $user_id;
|
||||
$ni->selectAdd();
|
||||
$ni->selectAdd('notice_id');
|
||||
$ni->orderBy('notice_id DESC');
|
||||
$ni->limit(0, 1024);
|
||||
|
||||
if ($ni->find()) {
|
||||
while($ni->fetch()) {
|
||||
$ids[] = $ni->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
$ni->free();
|
||||
unset($ni);
|
||||
|
||||
$inbox = new Inbox();
|
||||
|
||||
$inbox->user_id = $user_id;
|
||||
$inbox->notice_ids = call_user_func_array('pack', array_merge(array('N*'), $ids));
|
||||
$inbox->fake = true;
|
||||
|
||||
return $inbox;
|
||||
}
|
||||
|
||||
static function insertNotice($user_id, $notice_id)
|
||||
{
|
||||
$inbox = DB_DataObject::staticGet('inbox', 'user_id', $user_id);
|
||||
|
||||
if (empty($inbox)) {
|
||||
$inbox = Inbox::initialize($user_id);
|
||||
}
|
||||
|
||||
if (empty($inbox)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $inbox->query(sprintf('UPDATE inbox '.
|
||||
'set notice_ids = concat(cast(0x%08x as binary(4)), '.
|
||||
'substr(notice_ids, 1, 4092)) '.
|
||||
'WHERE user_id = %d',
|
||||
$notice_id, $user_id));
|
||||
|
||||
if ($result) {
|
||||
$c = self::memcache();
|
||||
|
||||
if (!empty($c)) {
|
||||
$c->delete(self::cacheKey('inbox', 'user_id', $user_id));
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
static function bulkInsert($notice_id, $user_ids)
|
||||
{
|
||||
foreach ($user_ids as $user_id)
|
||||
{
|
||||
Inbox::insertNotice($user_id, $notice_id);
|
||||
}
|
||||
}
|
||||
|
||||
function stream($user_id, $offset, $limit, $since_id, $max_id, $since, $own=false)
|
||||
{
|
||||
$inbox = Inbox::staticGet('user_id', $user_id);
|
||||
|
||||
if (empty($inbox)) {
|
||||
$inbox = Inbox::fromNoticeInbox($user_id);
|
||||
if (empty($inbox)) {
|
||||
return array();
|
||||
} else {
|
||||
$inbox->encache();
|
||||
}
|
||||
}
|
||||
|
||||
$ids = unpack('N*', $inbox->notice_ids);
|
||||
|
||||
if (!empty($since_id)) {
|
||||
$newids = array();
|
||||
foreach ($ids as $id) {
|
||||
if ($id > $since_id) {
|
||||
$newids[] = $id;
|
||||
}
|
||||
}
|
||||
$ids = $newids;
|
||||
}
|
||||
|
||||
if (!empty($max_id)) {
|
||||
$newids = array();
|
||||
foreach ($ids as $id) {
|
||||
if ($id <= $max_id) {
|
||||
$newids[] = $id;
|
||||
}
|
||||
}
|
||||
$ids = $newids;
|
||||
}
|
||||
|
||||
$ids = array_slice($ids, $offset, $limit);
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
|
@ -40,6 +40,8 @@ class Login_token extends Memcached_DataObject
|
|||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
const TIMEOUT = 120; // seconds after which to timeout the token
|
||||
|
||||
/*
|
||||
DB_DataObject calculates the sequence key(s) by taking the first key returned by the keys() function.
|
||||
In this case, the keys() function returns user_id as the first key. user_id is not a sequence, but
|
||||
|
@ -52,4 +54,29 @@ class Login_token extends Memcached_DataObject
|
|||
{
|
||||
return array(false,false);
|
||||
}
|
||||
|
||||
function makeNew($user)
|
||||
{
|
||||
$login_token = Login_token::staticGet('user_id', $user->id);
|
||||
|
||||
if (!empty($login_token)) {
|
||||
$login_token->delete();
|
||||
}
|
||||
|
||||
$login_token = new Login_token();
|
||||
|
||||
$login_token->user_id = $user->id;
|
||||
$login_token->token = common_good_rand(16);
|
||||
$login_token->created = common_sql_now();
|
||||
|
||||
$result = $login_token->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($login_token, 'INSERT', __FILE__);
|
||||
throw new Exception(sprintf(_('Could not create login token for %s'),
|
||||
$user->nickname));
|
||||
}
|
||||
|
||||
return $login_token;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Memcached_DataObject extends DB_DataObject
|
||||
{
|
||||
/**
|
||||
|
@ -66,6 +68,7 @@ class Memcached_DataObject extends DB_DataObject
|
|||
// Clear this out so we don't accidentally break global
|
||||
// state in *this* process.
|
||||
$this->_DB_resultid = null;
|
||||
|
||||
// We don't have any local DBO refs, so clear these out.
|
||||
$this->_link_loaded = false;
|
||||
}
|
||||
|
@ -90,7 +93,9 @@ class Memcached_DataObject extends DB_DataObject
|
|||
unset($i);
|
||||
}
|
||||
$i = Memcached_DataObject::getcached($cls, $k, $v);
|
||||
if ($i === false) { // false == cache miss
|
||||
if ($i) {
|
||||
return $i;
|
||||
} else {
|
||||
$i = DB_DataObject::factory($cls);
|
||||
if (empty($i)) {
|
||||
$i = false;
|
||||
|
@ -98,34 +103,22 @@ class Memcached_DataObject extends DB_DataObject
|
|||
}
|
||||
$result = $i->get($k, $v);
|
||||
if ($result) {
|
||||
// Hit!
|
||||
$i->encache();
|
||||
} else {
|
||||
// save the fact that no such row exists
|
||||
$c = self::memcache();
|
||||
if (!empty($c)) {
|
||||
$ck = self::cachekey($cls, $k, $v);
|
||||
$c->set($ck, null);
|
||||
}
|
||||
$i = false;
|
||||
}
|
||||
}
|
||||
return $i;
|
||||
} else {
|
||||
$i = false;
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @fixme Should this return false on lookup fail to match staticGet?
|
||||
*/
|
||||
function pkeyGet($cls, $kv)
|
||||
function &pkeyGet($cls, $kv)
|
||||
{
|
||||
$i = Memcached_DataObject::multicache($cls, $kv);
|
||||
if ($i !== false) { // false == cache miss
|
||||
if ($i) {
|
||||
return $i;
|
||||
} else {
|
||||
$i = DB_DataObject::factory($cls);
|
||||
if (empty($i)) {
|
||||
return false;
|
||||
}
|
||||
$i = new $cls();
|
||||
foreach ($kv as $k => $v) {
|
||||
$i->$k = $v;
|
||||
}
|
||||
|
@ -133,11 +126,6 @@ class Memcached_DataObject extends DB_DataObject
|
|||
$i->encache();
|
||||
} else {
|
||||
$i = null;
|
||||
$c = self::memcache();
|
||||
if (!empty($c)) {
|
||||
$ck = self::multicacheKey($cls, $kv);
|
||||
$c->set($ck, null);
|
||||
}
|
||||
}
|
||||
return $i;
|
||||
}
|
||||
|
@ -146,9 +134,6 @@ class Memcached_DataObject extends DB_DataObject
|
|||
function insert()
|
||||
{
|
||||
$result = parent::insert();
|
||||
if ($result) {
|
||||
$this->encache(); // in case of cached negative lookups
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -188,23 +173,21 @@ class Memcached_DataObject extends DB_DataObject
|
|||
if (!$c) {
|
||||
return false;
|
||||
} else {
|
||||
return $c->get(Memcached_DataObject::cacheKey($cls, $k, $v));
|
||||
$obj = $c->get(Memcached_DataObject::cacheKey($cls, $k, $v));
|
||||
if (0 == strcasecmp($cls, 'User')) {
|
||||
// Special case for User
|
||||
if (is_object($obj) && is_object($obj->id)) {
|
||||
common_log(LOG_ERR, "User " . $obj->nickname . " was cached with User as ID; deleting");
|
||||
$c->delete(Memcached_DataObject::cacheKey($cls, $k, $v));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
|
||||
function keyTypes()
|
||||
{
|
||||
// ini-based classes return number-indexed arrays. handbuilt
|
||||
// classes return column => keytype. Make this uniform.
|
||||
|
||||
$keys = $this->keys();
|
||||
|
||||
$keyskeys = array_keys($keys);
|
||||
|
||||
if (is_string($keyskeys[0])) {
|
||||
return $keys;
|
||||
}
|
||||
|
||||
global $_DB_DATAOBJECT;
|
||||
if (!isset($_DB_DATAOBJECT['INI'][$this->_database][$this->__table."__keys"])) {
|
||||
$this->databaseStructure();
|
||||
|
@ -216,88 +199,71 @@ class Memcached_DataObject extends DB_DataObject
|
|||
function encache()
|
||||
{
|
||||
$c = $this->memcache();
|
||||
|
||||
if (!$c) {
|
||||
return false;
|
||||
} else if ($this->tableName() == 'user' && is_object($this->id)) {
|
||||
// Special case for User bug
|
||||
$e = new Exception();
|
||||
common_log(LOG_ERR, __METHOD__ . ' caching user with User object as ID ' .
|
||||
str_replace("\n", " ", $e->getTraceAsString()));
|
||||
return false;
|
||||
} else {
|
||||
$pkey = array();
|
||||
$pval = array();
|
||||
$types = $this->keyTypes();
|
||||
ksort($types);
|
||||
foreach ($types as $key => $type) {
|
||||
if ($type == 'K') {
|
||||
$pkey[] = $key;
|
||||
$pval[] = $this->$key;
|
||||
} else {
|
||||
$c->set($this->cacheKey($this->tableName(), $key, $this->$key), $this);
|
||||
}
|
||||
|
||||
$keys = $this->_allCacheKeys();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$c->set($key, $this);
|
||||
}
|
||||
# XXX: should work for both compound and scalar pkeys
|
||||
$pvals = implode(',', $pval);
|
||||
$pkeys = implode(',', $pkey);
|
||||
$c->set($this->cacheKey($this->tableName(), $pkeys, $pvals), $this);
|
||||
}
|
||||
}
|
||||
|
||||
function decache()
|
||||
{
|
||||
$c = $this->memcache();
|
||||
|
||||
if (!$c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$keys = $this->_allCacheKeys();
|
||||
|
||||
foreach ($keys as $key) {
|
||||
$c->delete($key, $this);
|
||||
}
|
||||
}
|
||||
|
||||
function _allCacheKeys()
|
||||
{
|
||||
$ckeys = array();
|
||||
|
||||
$types = $this->keyTypes();
|
||||
ksort($types);
|
||||
|
||||
} else {
|
||||
$pkey = array();
|
||||
$pval = array();
|
||||
|
||||
$types = $this->keyTypes();
|
||||
ksort($types);
|
||||
foreach ($types as $key => $type) {
|
||||
|
||||
assert(!empty($key));
|
||||
|
||||
if ($type == 'U') {
|
||||
if (empty($this->$key)) {
|
||||
continue;
|
||||
}
|
||||
$ckeys[] = $this->cacheKey($this->tableName(), $key, $this->$key);
|
||||
} else if ($type == 'K' || $type == 'N') {
|
||||
if ($type == 'K') {
|
||||
$pkey[] = $key;
|
||||
$pval[] = $this->$key;
|
||||
} else {
|
||||
throw new Exception("Unknown key type $key => $type for " . $this->tableName());
|
||||
$c->delete($this->cacheKey($this->tableName(), $key, $this->$key));
|
||||
}
|
||||
}
|
||||
|
||||
assert(count($pkey) > 0);
|
||||
|
||||
// XXX: should work for both compound and scalar pkeys
|
||||
# should work for both compound and scalar pkeys
|
||||
# XXX: comma works for now but may not be safe separator for future keys
|
||||
$pvals = implode(',', $pval);
|
||||
$pkeys = implode(',', $pkey);
|
||||
|
||||
$ckeys[] = $this->cacheKey($this->tableName(), $pkeys, $pvals);
|
||||
|
||||
return $ckeys;
|
||||
$c->delete($this->cacheKey($this->tableName(), $pkeys, $pvals));
|
||||
}
|
||||
}
|
||||
|
||||
function multicache($cls, $kv)
|
||||
{
|
||||
ksort($kv);
|
||||
$c = self::memcache();
|
||||
$c = Memcached_DataObject::memcache();
|
||||
if (!$c) {
|
||||
return false;
|
||||
} else {
|
||||
return $c->get(self::multicacheKey($cls, $kv));
|
||||
}
|
||||
}
|
||||
|
||||
static function multicacheKey($cls, $kv)
|
||||
{
|
||||
ksort($kv);
|
||||
$pkeys = implode(',', array_keys($kv));
|
||||
$pvals = implode(',', array_values($kv));
|
||||
return self::cacheKey($cls, $pkeys, $pvals);
|
||||
return $c->get(Memcached_DataObject::cacheKey($cls, $pkeys, $pvals));
|
||||
}
|
||||
}
|
||||
|
||||
function getSearchEngine($table)
|
||||
|
@ -334,8 +300,7 @@ class Memcached_DataObject extends DB_DataObject
|
|||
$key_part = common_keyize($cls).':'.md5($qry);
|
||||
$ckey = common_cache_key($key_part);
|
||||
$stored = $c->get($ckey);
|
||||
|
||||
if ($stored !== false) {
|
||||
if ($stored) {
|
||||
return new ArrayWrapper($stored);
|
||||
}
|
||||
|
||||
|
@ -366,6 +331,29 @@ class Memcached_DataObject extends DB_DataObject
|
|||
$exists = false;
|
||||
}
|
||||
|
||||
// @fixme horrible evil hack!
|
||||
//
|
||||
// In multisite configuration we don't want to keep around a separate
|
||||
// connection for every database; we could end up with thousands of
|
||||
// connections open per thread. In an ideal world we might keep
|
||||
// a connection per server and select different databases, but that'd
|
||||
// be reliant on having the same db username/pass as well.
|
||||
//
|
||||
// MySQL connections are cheap enough we're going to try just
|
||||
// closing out the old connection and reopening when we encounter
|
||||
// a new DSN.
|
||||
//
|
||||
// WARNING WARNING if we end up actually using multiple DBs at a time
|
||||
// we'll need some fancier logic here.
|
||||
if (!$exists && !empty($_DB_DATAOBJECT['CONNECTIONS'])) {
|
||||
foreach ($_DB_DATAOBJECT['CONNECTIONS'] as $index => $conn) {
|
||||
if (!empty($conn)) {
|
||||
$conn->disconnect();
|
||||
}
|
||||
unset($_DB_DATAOBJECT['CONNECTIONS'][$index]);
|
||||
}
|
||||
}
|
||||
|
||||
$result = parent::_connect();
|
||||
|
||||
if ($result && !$exists) {
|
||||
|
|
|
@ -125,8 +125,7 @@ class Notice extends Memcached_DataObject
|
|||
'Fave',
|
||||
'Notice_tag',
|
||||
'Group_inbox',
|
||||
'Queue_item',
|
||||
'Notice_inbox');
|
||||
'Queue_item');
|
||||
|
||||
foreach ($related as $cls) {
|
||||
$inst = new $cls();
|
||||
|
@ -276,7 +275,6 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
if (isset($repeat_of)) {
|
||||
$notice->repeat_of = $repeat_of;
|
||||
$notice->reply_to = $repeat_of;
|
||||
} else {
|
||||
$notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final);
|
||||
}
|
||||
|
@ -300,8 +298,6 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
// XXX: some of these functions write to the DB
|
||||
|
||||
$notice->query('BEGIN');
|
||||
|
||||
$id = $notice->insert();
|
||||
|
||||
if (!$id) {
|
||||
|
@ -339,12 +335,14 @@ class Notice extends Memcached_DataObject
|
|||
|
||||
$notice->saveTags();
|
||||
|
||||
$notice->addToInboxes();
|
||||
$groups = $notice->saveGroups();
|
||||
|
||||
$recipients = $notice->saveReplies();
|
||||
|
||||
$notice->addToInboxes($groups, $recipients);
|
||||
|
||||
$notice->saveUrls();
|
||||
|
||||
$notice->query('COMMIT');
|
||||
|
||||
Event::handle('EndNoticeSave', array($notice));
|
||||
}
|
||||
|
||||
|
@ -503,20 +501,6 @@ class Notice extends Memcached_DataObject
|
|||
$original->free();
|
||||
unset($original);
|
||||
}
|
||||
|
||||
$ni = new Notice_inbox();
|
||||
|
||||
$ni->notice_id = $this->id;
|
||||
|
||||
if ($ni->find()) {
|
||||
while ($ni->fetch()) {
|
||||
$tmk = common_cache_key('user:repeated_to_me:'.$ni->user_id);
|
||||
$cache->delete($tmk);
|
||||
}
|
||||
}
|
||||
|
||||
$ni->free();
|
||||
unset($ni);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -842,11 +826,28 @@ class Notice extends Memcached_DataObject
|
|||
return $ids;
|
||||
}
|
||||
|
||||
function addToInboxes()
|
||||
/**
|
||||
* @param $groups array of Group *objects*
|
||||
* @param $recipients array of profile *ids*
|
||||
*/
|
||||
function whoGets($groups=null, $recipients=null)
|
||||
{
|
||||
// XXX: loads constants
|
||||
$c = self::memcache();
|
||||
|
||||
$inbox = new Notice_inbox();
|
||||
if (!empty($c)) {
|
||||
$ni = $c->get(common_cache_key('notice:who_gets:'.$this->id));
|
||||
if ($ni !== false) {
|
||||
return $ni;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($groups)) {
|
||||
$groups = $this->getGroups();
|
||||
}
|
||||
|
||||
if (is_null($recipients)) {
|
||||
$recipients = $this->getReplies();
|
||||
}
|
||||
|
||||
$users = $this->getSubscribedUsers();
|
||||
|
||||
|
@ -860,7 +861,6 @@ class Notice extends Memcached_DataObject
|
|||
$ni[$id] = NOTICE_INBOX_SOURCE_SUB;
|
||||
}
|
||||
|
||||
$groups = $this->saveGroups();
|
||||
$profile = $this->getProfile();
|
||||
|
||||
foreach ($groups as $group) {
|
||||
|
@ -875,8 +875,6 @@ class Notice extends Memcached_DataObject
|
|||
}
|
||||
}
|
||||
|
||||
$recipients = $this->saveReplies();
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
|
||||
if (!array_key_exists($recipient, $ni)) {
|
||||
|
@ -887,7 +885,19 @@ class Notice extends Memcached_DataObject
|
|||
}
|
||||
}
|
||||
|
||||
Notice_inbox::bulkInsert($this->id, $this->created, $ni);
|
||||
if (!empty($c)) {
|
||||
// XXX: pack this data better
|
||||
$c->set(common_cache_key('notice:who_gets:'.$this->id), $ni);
|
||||
}
|
||||
|
||||
return $ni;
|
||||
}
|
||||
|
||||
function addToInboxes($groups, $recipients)
|
||||
{
|
||||
$ni = $this->whoGets($groups, $recipients);
|
||||
|
||||
Inbox::bulkInsert($this->id, array_keys($ni));
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -919,8 +929,17 @@ class Notice extends Memcached_DataObject
|
|||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array of Group objects
|
||||
*/
|
||||
function saveGroups()
|
||||
{
|
||||
// Don't save groups for repeats
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$groups = array();
|
||||
|
||||
/* extract all !group */
|
||||
|
@ -991,6 +1010,12 @@ class Notice extends Memcached_DataObject
|
|||
*/
|
||||
function saveReplies()
|
||||
{
|
||||
// Don't save reply data for repeats
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Alternative reply format
|
||||
$tname = false;
|
||||
if (preg_match('/^T ([A-Z0-9]{1,64}) /', $this->content, $match)) {
|
||||
|
@ -1077,6 +1102,63 @@ class Notice extends Memcached_DataObject
|
|||
return $recipientIds;
|
||||
}
|
||||
|
||||
function getReplies()
|
||||
{
|
||||
// XXX: cache me
|
||||
|
||||
$ids = array();
|
||||
|
||||
$reply = new Reply();
|
||||
$reply->selectAdd();
|
||||
$reply->selectAdd('profile_id');
|
||||
$reply->notice_id = $this->id;
|
||||
|
||||
if ($reply->find()) {
|
||||
while($reply->fetch()) {
|
||||
$ids[] = $reply->profile_id;
|
||||
}
|
||||
}
|
||||
|
||||
$reply->free();
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same calculation as saveGroups but without the saving
|
||||
* @fixme merge the functions
|
||||
* @return array of Group objects
|
||||
*/
|
||||
function getGroups()
|
||||
{
|
||||
// Don't save groups for repeats
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// XXX: cache me
|
||||
|
||||
$groups = array();
|
||||
|
||||
$gi = new Group_inbox();
|
||||
|
||||
$gi->selectAdd();
|
||||
$gi->selectAdd('group_id');
|
||||
|
||||
$gi->notice_id = $this->id;
|
||||
|
||||
if ($gi->find()) {
|
||||
while ($gi->fetch()) {
|
||||
$groups[] = clone($gi);
|
||||
}
|
||||
}
|
||||
|
||||
$gi->free();
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
function asAtomEntry($namespace=false, $source=false)
|
||||
{
|
||||
$profile = $this->getProfile();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
/*
|
||||
* StatusNet - the distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, 2009, StatusNet, Inc.
|
||||
* Copyright (C) 2008-2010, 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
|
||||
|
@ -17,7 +17,9 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
|
@ -29,12 +31,6 @@ define('NOTICE_INBOX_GC_MAX', 12800);
|
|||
define('NOTICE_INBOX_LIMIT', 1000);
|
||||
define('NOTICE_INBOX_SOFT_LIMIT', 1000);
|
||||
|
||||
define('NOTICE_INBOX_SOURCE_SUB', 1);
|
||||
define('NOTICE_INBOX_SOURCE_GROUP', 2);
|
||||
define('NOTICE_INBOX_SOURCE_REPLY', 3);
|
||||
define('NOTICE_INBOX_SOURCE_FORWARD', 4);
|
||||
define('NOTICE_INBOX_SOURCE_GATEWAY', -1);
|
||||
|
||||
class Notice_inbox extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
|
@ -55,139 +51,31 @@ class Notice_inbox extends Memcached_DataObject
|
|||
|
||||
function stream($user_id, $offset, $limit, $since_id, $max_id, $since, $own=false)
|
||||
{
|
||||
return Notice::stream(array('Notice_inbox', '_streamDirect'),
|
||||
array($user_id, $own),
|
||||
($own) ? 'notice_inbox:by_user:'.$user_id :
|
||||
'notice_inbox:by_user_own:'.$user_id,
|
||||
$offset, $limit, $since_id, $max_id, $since);
|
||||
throw new Exception('Notice_inbox no longer used; use Inbox');
|
||||
}
|
||||
|
||||
function _streamDirect($user_id, $own, $offset, $limit, $since_id, $max_id, $since)
|
||||
{
|
||||
$inbox = new Notice_inbox();
|
||||
|
||||
$inbox->user_id = $user_id;
|
||||
|
||||
if (!$own) {
|
||||
$inbox->whereAdd('source != ' . NOTICE_INBOX_SOURCE_GATEWAY);
|
||||
throw new Exception('Notice_inbox no longer used; use Inbox');
|
||||
}
|
||||
|
||||
if ($since_id != 0) {
|
||||
$inbox->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$inbox->whereAdd('notice_id <= ' . $max_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$inbox->whereAdd('created > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||
}
|
||||
|
||||
$inbox->orderBy('created DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$inbox->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($inbox->find()) {
|
||||
while ($inbox->fetch()) {
|
||||
$ids[] = $inbox->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function pkeyGet($kv)
|
||||
function &pkeyGet($kv)
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Notice_inbox', $kv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim inbox for a given user to latest NOTICE_INBOX_LIMIT items
|
||||
* (up to NOTICE_INBOX_GC_MAX will be deleted).
|
||||
*
|
||||
* @param int $user_id
|
||||
* @return int count of notices dropped from the inbox, if any
|
||||
*/
|
||||
static function gc($user_id)
|
||||
{
|
||||
$entry = new Notice_inbox();
|
||||
$entry->user_id = $user_id;
|
||||
$entry->orderBy('created DESC');
|
||||
$entry->limit(NOTICE_INBOX_LIMIT - 1, NOTICE_INBOX_GC_MAX);
|
||||
|
||||
$total = $entry->find();
|
||||
|
||||
if ($total > 0) {
|
||||
$notices = array();
|
||||
$cnt = 0;
|
||||
while ($entry->fetch()) {
|
||||
$notices[] = $entry->notice_id;
|
||||
$cnt++;
|
||||
if ($cnt >= NOTICE_INBOX_GC_BOXCAR) {
|
||||
self::deleteMatching($user_id, $notices);
|
||||
$notices = array();
|
||||
$cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($cnt > 0) {
|
||||
self::deleteMatching($user_id, $notices);
|
||||
$notices = array();
|
||||
}
|
||||
}
|
||||
|
||||
return $total;
|
||||
throw new Exception('Notice_inbox no longer used; use Inbox');
|
||||
}
|
||||
|
||||
static function deleteMatching($user_id, $notices)
|
||||
{
|
||||
$entry = new Notice_inbox();
|
||||
return $entry->query('DELETE FROM notice_inbox '.
|
||||
'WHERE user_id = ' . $user_id . ' ' .
|
||||
'AND notice_id in ('.implode(',', $notices).')');
|
||||
throw new Exception('Notice_inbox no longer used; use Inbox');
|
||||
}
|
||||
|
||||
static function bulkInsert($notice_id, $created, $ni)
|
||||
{
|
||||
$cnt = 0;
|
||||
|
||||
$qryhdr = 'INSERT INTO notice_inbox (user_id, notice_id, source, created) VALUES ';
|
||||
$qry = $qryhdr;
|
||||
|
||||
foreach ($ni as $id => $source) {
|
||||
if ($cnt > 0) {
|
||||
$qry .= ', ';
|
||||
}
|
||||
$qry .= '('.$id.', '.$notice_id.', '.$source.", '".$created. "') ";
|
||||
$cnt++;
|
||||
if (rand() % NOTICE_INBOX_SOFT_LIMIT == 0) {
|
||||
// FIXME: Causes lag in replicated servers
|
||||
// Notice_inbox::gc($id);
|
||||
}
|
||||
if ($cnt >= MAX_BOXCARS) {
|
||||
$inbox = new Notice_inbox();
|
||||
$result = $inbox->query($qry);
|
||||
if (PEAR::isError($result)) {
|
||||
common_log_db_error($inbox, $qry);
|
||||
}
|
||||
$qry = $qryhdr;
|
||||
$cnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($cnt > 0) {
|
||||
$inbox = new Notice_inbox();
|
||||
$result = $inbox->query($qry);
|
||||
if (PEAR::isError($result)) {
|
||||
common_log_db_error($inbox, $qry);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
throw new Exception('Notice_inbox no longer used; use Inbox');
|
||||
}
|
||||
}
|
||||
|
|
140
classes/Oauth_application.php
Normal file
140
classes/Oauth_application.php
Normal file
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
/**
|
||||
* Table Definition for oauth_application
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Oauth_application extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'oauth_application'; // table name
|
||||
public $id; // int(4) primary_key not_null
|
||||
public $owner; // int(4) not_null
|
||||
public $consumer_key; // varchar(255) not_null
|
||||
public $name; // varchar(255) not_null
|
||||
public $description; // varchar(255)
|
||||
public $icon; // varchar(255) not_null
|
||||
public $source_url; // varchar(255)
|
||||
public $organization; // varchar(255)
|
||||
public $homepage; // varchar(255)
|
||||
public $callback_url; // varchar(255) not_null
|
||||
public $type; // tinyint(1)
|
||||
public $access_type; // tinyint(1)
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) {
|
||||
return Memcached_DataObject::staticGet('Oauth_application',$k,$v);
|
||||
}
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
// Bit flags
|
||||
public static $readAccess = 1;
|
||||
public static $writeAccess = 2;
|
||||
|
||||
public static $browser = 1;
|
||||
public static $desktop = 2;
|
||||
|
||||
function getConsumer()
|
||||
{
|
||||
return Consumer::staticGet('consumer_key', $this->consumer_key);
|
||||
}
|
||||
|
||||
static function maxDesc()
|
||||
{
|
||||
$desclimit = common_config('application', 'desclimit');
|
||||
// null => use global limit (distinct from 0!)
|
||||
if (is_null($desclimit)) {
|
||||
$desclimit = common_config('site', 'textlimit');
|
||||
}
|
||||
return $desclimit;
|
||||
}
|
||||
|
||||
static function descriptionTooLong($desc)
|
||||
{
|
||||
$desclimit = self::maxDesc();
|
||||
return ($desclimit > 0 && !empty($desc) && (mb_strlen($desc) > $desclimit));
|
||||
}
|
||||
|
||||
function setAccessFlags($read, $write)
|
||||
{
|
||||
if ($read) {
|
||||
$this->access_type |= self::$readAccess;
|
||||
} else {
|
||||
$this->access_type &= ~self::$readAccess;
|
||||
}
|
||||
|
||||
if ($write) {
|
||||
$this->access_type |= self::$writeAccess;
|
||||
} else {
|
||||
$this->access_type &= ~self::$writeAccess;
|
||||
}
|
||||
}
|
||||
|
||||
function setOriginal($filename)
|
||||
{
|
||||
$imagefile = new ImageFile($this->id, Avatar::path($filename));
|
||||
|
||||
// XXX: Do we want to have a bunch of different size icons? homepage, stream, mini?
|
||||
// or just one and control size via CSS? --Zach
|
||||
|
||||
$orig = clone($this);
|
||||
$this->icon = Avatar::url($filename);
|
||||
common_debug(common_log_objstring($this));
|
||||
return $this->update($orig);
|
||||
}
|
||||
|
||||
static function getByConsumerKey($key)
|
||||
{
|
||||
if (empty($key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$app = new Oauth_application();
|
||||
$app->consumer_key = $key;
|
||||
$app->limit(1);
|
||||
$result = $app->find(true);
|
||||
|
||||
return empty($result) ? null : $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an image upload
|
||||
*
|
||||
* Does all the magic for handling an image upload, and crops the
|
||||
* image by default.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function uploadLogo()
|
||||
{
|
||||
if ($_FILES['app_icon']['error'] ==
|
||||
UPLOAD_ERR_OK) {
|
||||
|
||||
try {
|
||||
$imagefile = ImageFile::fromUpload('app_icon');
|
||||
} catch (Exception $e) {
|
||||
common_debug("damn that sucks");
|
||||
$this->showForm($e->getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
$filename = Avatar::filename($this->id,
|
||||
image_type_to_extension($imagefile->type),
|
||||
null,
|
||||
'oauth-app-icon-'.common_timestamp());
|
||||
|
||||
$filepath = Avatar::path($filename);
|
||||
|
||||
move_uploaded_file($imagefile->filepath, $filepath);
|
||||
|
||||
$this->setOriginal($filename);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
44
classes/Oauth_application_user.php
Normal file
44
classes/Oauth_application_user.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* Table Definition for oauth_application_user
|
||||
*/
|
||||
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
|
||||
|
||||
class Oauth_application_user extends Memcached_DataObject
|
||||
{
|
||||
###START_AUTOCODE
|
||||
/* the code below is auto generated do not remove the above tag */
|
||||
|
||||
public $__table = 'oauth_application_user'; // table name
|
||||
public $profile_id; // int(4) primary_key not_null
|
||||
public $application_id; // int(4) primary_key not_null
|
||||
public $access_type; // tinyint(1)
|
||||
public $token; // varchar(255)
|
||||
public $created; // datetime not_null
|
||||
public $modified; // timestamp not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
/* Static get */
|
||||
function staticGet($k,$v=NULL) {
|
||||
return Memcached_DataObject::staticGet('Oauth_application_user',$k,$v);
|
||||
}
|
||||
/* the code above is auto generated do not remove the tag below */
|
||||
###END_AUTOCODE
|
||||
|
||||
static function getByKeys($user, $app)
|
||||
{
|
||||
if (empty($user) || empty($app)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$oau = new Oauth_application_user();
|
||||
|
||||
$oau->profile_id = $user->id;
|
||||
$oau->application_id = $app->id;
|
||||
$oau->limit(1);
|
||||
|
||||
$result = $oau->find(true);
|
||||
|
||||
return empty($result) ? null : $oau;
|
||||
}
|
||||
|
||||
}
|
|
@ -352,6 +352,31 @@ class Profile extends Memcached_DataObject
|
|||
return $profile;
|
||||
}
|
||||
|
||||
function getApplications($offset = 0, $limit = null)
|
||||
{
|
||||
$qry =
|
||||
'SELECT a.* ' .
|
||||
'FROM oauth_application_user u, oauth_application a ' .
|
||||
'WHERE u.profile_id = %d ' .
|
||||
'AND a.id = u.application_id ' .
|
||||
'AND u.access_type > 0 ' .
|
||||
'ORDER BY u.created DESC ';
|
||||
|
||||
if ($offset > 0) {
|
||||
if (common_config('db','type') == 'pgsql') {
|
||||
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
|
||||
} else {
|
||||
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
|
||||
}
|
||||
}
|
||||
|
||||
$application = new Oauth_application();
|
||||
|
||||
$cnt = $application->query(sprintf($qry, $this->id));
|
||||
|
||||
return $application;
|
||||
}
|
||||
|
||||
function subscriptionCount()
|
||||
{
|
||||
$c = common_memcache();
|
||||
|
|
|
@ -25,10 +25,12 @@ class Queue_item extends Memcached_DataObject
|
|||
function sequenceKey()
|
||||
{ return array(false, false); }
|
||||
|
||||
static function top($transport) {
|
||||
static function top($transport=null) {
|
||||
|
||||
$qi = new Queue_item();
|
||||
if ($transport) {
|
||||
$qi->transport = $transport;
|
||||
}
|
||||
$qi->orderBy('created');
|
||||
$qi->whereAdd('claimed is null');
|
||||
|
||||
|
@ -40,7 +42,8 @@ class Queue_item extends Memcached_DataObject
|
|||
# XXX: potential race condition
|
||||
# can we force it to only update if claimed is still null
|
||||
# (or old)?
|
||||
common_log(LOG_INFO, 'claiming queue item = ' . $qi->notice_id . ' for transport ' . $transport);
|
||||
common_log(LOG_INFO, 'claiming queue item = ' . $qi->notice_id .
|
||||
' for transport ' . $qi->transport);
|
||||
$orig = clone($qi);
|
||||
$qi->claimed = common_sql_now();
|
||||
$result = $qi->update($orig);
|
||||
|
|
|
@ -49,6 +49,13 @@ class Status_network extends DB_DataObject
|
|||
static $cache = null;
|
||||
static $base = null;
|
||||
|
||||
/**
|
||||
* @param string $dbhost
|
||||
* @param string $dbuser
|
||||
* @param string $dbpass
|
||||
* @param string $dbname
|
||||
* @param array $servers memcached servers to use for caching config info
|
||||
*/
|
||||
static function setupDB($dbhost, $dbuser, $dbpass, $dbname, $servers)
|
||||
{
|
||||
global $config;
|
||||
|
@ -60,12 +67,17 @@ class Status_network extends DB_DataObject
|
|||
if (class_exists('Memcache')) {
|
||||
self::$cache = new Memcache();
|
||||
|
||||
// Can't close persistent connections, making forking painful.
|
||||
//
|
||||
// @fixme only do this in *parent* CLI processes.
|
||||
// single-process and child-processes *should* use persistent.
|
||||
$persist = php_sapi_name() != 'cli';
|
||||
if (is_array($servers)) {
|
||||
foreach($servers as $server) {
|
||||
self::$cache->addServer($server);
|
||||
self::$cache->addServer($server, 11211, $persist);
|
||||
}
|
||||
} else {
|
||||
self::$cache->addServer($servers);
|
||||
self::$cache->addServer($servers, 11211, $persist);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,7 +101,7 @@ class Status_network extends DB_DataObject
|
|||
if (empty($sn)) {
|
||||
$sn = self::staticGet($k, $v);
|
||||
if (!empty($sn)) {
|
||||
self::$cache->set($ck, $sn);
|
||||
self::$cache->set($ck, clone($sn));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,6 +133,11 @@ class Status_network extends DB_DataObject
|
|||
return parent::delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $servername hostname
|
||||
* @param string $pathname URL base path
|
||||
* @param string $wildcard hostname suffix to match wildcard config
|
||||
*/
|
||||
static function setupSite($servername, $pathname, $wildcard)
|
||||
{
|
||||
global $config;
|
||||
|
@ -150,9 +167,19 @@ class Status_network extends DB_DataObject
|
|||
}
|
||||
|
||||
if (!empty($sn)) {
|
||||
if (!empty($sn->hostname) && 0 != strcasecmp($sn->hostname, $servername)) {
|
||||
$sn->redirectToHostname();
|
||||
|
||||
// Redirect to the right URL
|
||||
|
||||
if (!empty($sn->hostname) &&
|
||||
empty($_SERVER['HTTPS']) &&
|
||||
0 != strcasecmp($sn->hostname, $servername)) {
|
||||
$sn->redirectTo('http://'.$sn->hostname.$_SERVER['REQUEST_URI']);
|
||||
} else if (!empty($_SERVER['HTTPS']) &&
|
||||
0 != strcasecmp($sn->hostname, $servername) &&
|
||||
0 != strcasecmp($sn->nickname.'.'.$wildcard, $servername)) {
|
||||
$sn->redirectTo('https://'.$sn->nickname.'.'.$wildcard.$_SERVER['REQUEST_URI']);
|
||||
}
|
||||
|
||||
$dbhost = (empty($sn->dbhost)) ? 'localhost' : $sn->dbhost;
|
||||
$dbuser = (empty($sn->dbuser)) ? $sn->nickname : $sn->dbuser;
|
||||
$dbpass = $sn->dbpass;
|
||||
|
@ -162,6 +189,10 @@ class Status_network extends DB_DataObject
|
|||
|
||||
$config['site']['name'] = $sn->sitename;
|
||||
|
||||
if (!empty($sn->hostname)) {
|
||||
$config['site']['server'] = $sn->hostname;
|
||||
}
|
||||
|
||||
if (!empty($sn->theme)) {
|
||||
$config['site']['theme'] = $sn->theme;
|
||||
}
|
||||
|
@ -179,11 +210,8 @@ class Status_network extends DB_DataObject
|
|||
// (C) 2006 by Heiko Richler http://www.richler.de/
|
||||
// LGPL
|
||||
|
||||
function redirectToHostname()
|
||||
function redirectTo($destination)
|
||||
{
|
||||
$destination = 'http://'.$this->hostname;
|
||||
$destination .= $_SERVER['REQUEST_URI'];
|
||||
|
||||
$old = 'http'.
|
||||
(($_SERVER['HTTPS'] == 'on') ? 'S' : '').
|
||||
'://'.
|
||||
|
|
|
@ -15,6 +15,8 @@ class Token extends Memcached_DataObject
|
|||
public $secret; // char(32) not_null
|
||||
public $type; // tinyint(1) not_null
|
||||
public $state; // tinyint(1)
|
||||
public $verifier; // varchar(255)
|
||||
public $verified_callback; // varchar(255)
|
||||
public $created; // datetime() not_null
|
||||
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
|
||||
|
||||
|
|
133
classes/User.php
133
classes/User.php
|
@ -291,6 +291,20 @@ class User extends Memcached_DataObject
|
|||
return false;
|
||||
}
|
||||
|
||||
// Everyone gets an inbox
|
||||
|
||||
$inbox = new Inbox();
|
||||
|
||||
$inbox->user_id = $user->id;
|
||||
$inbox->notice_ids = '';
|
||||
|
||||
$result = $inbox->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($inbox, 'INSERT', __FILE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everyone is subscribed to themself
|
||||
|
||||
$subscription = new Subscription();
|
||||
|
@ -482,89 +496,30 @@ class User extends Memcached_DataObject
|
|||
|
||||
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||
{
|
||||
$ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false);
|
||||
|
||||
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false);
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function noticeInbox($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||
{
|
||||
$ids = Notice_inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true);
|
||||
|
||||
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true);
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function friendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_friendsTimelineDirect'),
|
||||
array(false),
|
||||
'user:friends_timeline:'.$this->id,
|
||||
$offset, $limit, $since_id, $before_id, $since);
|
||||
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function ownFriendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_friendsTimelineDirect'),
|
||||
array(true),
|
||||
'user:friends_timeline_own:'.$this->id,
|
||||
$offset, $limit, $since_id, $before_id, $since);
|
||||
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _friendsTimelineDirect($own, $offset, $limit, $since_id, $max_id, $since)
|
||||
{
|
||||
$qry =
|
||||
'SELECT notice.id AS id ' .
|
||||
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
||||
'WHERE notice_inbox.user_id = ' . $this->id . ' ' .
|
||||
'AND notice.repeat_of IS NULL ';
|
||||
|
||||
if (!$own) {
|
||||
// XXX: autoload notice inbox for constant
|
||||
$inbox = new Notice_inbox();
|
||||
|
||||
$qry .= 'AND notice_inbox.source != ' . NOTICE_INBOX_SOURCE_GATEWAY . ' ';
|
||||
}
|
||||
|
||||
if ($since_id != 0) {
|
||||
$qry .= 'AND notice.id > ' . $since_id . ' ';
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$qry .= 'AND notice.id <= ' . $max_id . ' ';
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$qry .= 'AND notice.modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$qry .= 'ORDER BY notice_id DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->query($qry);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function blowFavesCache()
|
||||
{
|
||||
$cache = common_memcache();
|
||||
|
@ -777,7 +732,6 @@ class User extends Memcached_DataObject
|
|||
'Remember_me',
|
||||
'Foreign_link',
|
||||
'Invitation',
|
||||
'Notice_inbox',
|
||||
);
|
||||
Event::handle('UserDeleteRelated', array($this, &$related));
|
||||
|
||||
|
@ -945,56 +899,7 @@ class User extends Memcached_DataObject
|
|||
|
||||
function repeatedToMe($offset=0, $limit=20, $since_id=null, $max_id=null)
|
||||
{
|
||||
$ids = Notice::stream(array($this, '_repeatedToMeDirect'),
|
||||
array(),
|
||||
'user:repeated_to_me:'.$this->id,
|
||||
$offset, $limit, $since_id, $max_id, null);
|
||||
|
||||
return Notice::getStreamByIds($ids);
|
||||
}
|
||||
|
||||
function _repeatedToMeDirect($offset, $limit, $since_id, $max_id, $since)
|
||||
{
|
||||
$qry =
|
||||
'SELECT notice.id AS id ' .
|
||||
'FROM notice JOIN notice_inbox ON notice.id = notice_inbox.notice_id ' .
|
||||
'WHERE notice_inbox.user_id = ' . $this->id . ' ' .
|
||||
'AND notice.repeat_of IS NOT NULL ';
|
||||
|
||||
if ($since_id != 0) {
|
||||
$qry .= 'AND notice.id > ' . $since_id . ' ';
|
||||
}
|
||||
|
||||
if ($max_id != 0) {
|
||||
$qry .= 'AND notice.id <= ' . $max_id . ' ';
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$qry .= 'AND notice.modified > \'' . date('Y-m-d H:i:s', $since) . '\' ';
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$qry .= 'ORDER BY notice.id DESC ';
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$qry .= "LIMIT $limit OFFSET $offset";
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
$notice->query($qry);
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$ids[] = $notice->id;
|
||||
}
|
||||
|
||||
$notice->free();
|
||||
$notice = NULL;
|
||||
|
||||
return $ids;
|
||||
throw new Exception("Not implemented since inbox change.");
|
||||
}
|
||||
|
||||
function shareLocation()
|
||||
|
|
|
@ -39,6 +39,7 @@ code = K
|
|||
|
||||
[consumer]
|
||||
consumer_key = 130
|
||||
consumer_secret = 130
|
||||
seed = 130
|
||||
created = 142
|
||||
modified = 384
|
||||
|
@ -241,6 +242,13 @@ address = 130
|
|||
address_type = 130
|
||||
created = 142
|
||||
|
||||
[inbox]
|
||||
user_id = 129
|
||||
notice_ids = 66
|
||||
|
||||
[inbox__keys]
|
||||
user_id = K
|
||||
|
||||
[invitation__keys]
|
||||
code = K
|
||||
|
||||
|
@ -341,6 +349,37 @@ created = 142
|
|||
tag = K
|
||||
notice_id = K
|
||||
|
||||
[oauth_application]
|
||||
id = 129
|
||||
owner = 129
|
||||
consumer_key = 130
|
||||
name = 130
|
||||
description = 2
|
||||
icon = 130
|
||||
source_url = 2
|
||||
organization = 2
|
||||
homepage = 2
|
||||
callback_url = 130
|
||||
type = 17
|
||||
access_type = 17
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[oauth_application__keys]
|
||||
id = N
|
||||
|
||||
[oauth_application_user]
|
||||
profile_id = 129
|
||||
application_id = 129
|
||||
access_type = 17
|
||||
token = 2
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
[oauth_application_user__keys]
|
||||
profile_id = K
|
||||
application_id = K
|
||||
|
||||
[profile]
|
||||
id = 129
|
||||
nickname = 130
|
||||
|
@ -477,6 +516,8 @@ tok = 130
|
|||
secret = 130
|
||||
type = 145
|
||||
state = 17
|
||||
verifier = 2
|
||||
verified_callback = 2
|
||||
created = 142
|
||||
modified = 384
|
||||
|
||||
|
|
17
db/rc2torc3.sql
Normal file
17
db/rc2torc3.sql
Normal file
|
@ -0,0 +1,17 @@
|
|||
create table user_location_prefs (
|
||||
user_id integer not null comment 'user who has the preference' references user (id),
|
||||
share_location tinyint default 1 comment 'Whether to share location data',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
||||
constraint primary key (user_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table inbox (
|
||||
|
||||
user_id integer not null comment 'user receiving the notice' references user (id),
|
||||
notice_ids blob comment 'packed list of notice ids',
|
||||
|
||||
constraint primary key (user_id)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
|
@ -176,6 +176,7 @@ create table fave (
|
|||
|
||||
create table consumer (
|
||||
consumer_key varchar(255) primary key comment 'unique identifier, root URL',
|
||||
consumer_secret varchar(255) not null comment 'secret value',
|
||||
seed char(32) not null comment 'seed for new tokens by this consumer',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
|
@ -188,6 +189,8 @@ create table token (
|
|||
secret char(32) not null comment 'secret value',
|
||||
type tinyint not null default 0 comment 'request or access',
|
||||
state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used',
|
||||
verifier varchar(255) comment 'verifier string for OAuth 1.0a',
|
||||
verified_callback varchar(255) comment 'verified callback URL for OAuth 1.0a',
|
||||
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
|
@ -207,6 +210,33 @@ create table nonce (
|
|||
constraint primary key (consumer_key, ts, nonce)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table oauth_application (
|
||||
id integer auto_increment primary key comment 'unique identifier',
|
||||
owner integer not null comment 'owner of the application' references profile (id),
|
||||
consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key),
|
||||
name varchar(255) not null comment 'name of the application',
|
||||
description varchar(255) comment 'description of the application',
|
||||
icon varchar(255) not null comment 'application icon',
|
||||
source_url varchar(255) comment 'application homepage - used for source link',
|
||||
organization varchar(255) comment 'name of the organization running the application',
|
||||
homepage varchar(255) comment 'homepage for the organization',
|
||||
callback_url varchar(255) comment 'url to redirect to after authentication',
|
||||
type tinyint default 0 comment 'type of app, 1 = browser, 2 = desktop',
|
||||
access_type tinyint default 0 comment 'default access type, bit 1 = read, bit 2 = write',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified'
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table oauth_application_user (
|
||||
profile_id integer not null comment 'user of the application' references profile (id),
|
||||
application_id integer not null comment 'id of the application' references oauth_application (id),
|
||||
access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked',
|
||||
token varchar(255) comment 'request or access token',
|
||||
created datetime not null comment 'date this record was created',
|
||||
modified timestamp comment 'date this record was modified',
|
||||
constraint primary key (profile_id, application_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
/* These are used by JanRain OpenID library */
|
||||
|
||||
create table oid_associations (
|
||||
|
@ -596,3 +626,11 @@ create table user_location_prefs (
|
|||
constraint primary key (user_id)
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
||||
create table inbox (
|
||||
|
||||
user_id integer not null comment 'user receiving the notice' references user (id),
|
||||
notice_ids blob comment 'packed list of notice ids',
|
||||
|
||||
constraint primary key (user_id)
|
||||
|
||||
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
|
||||
|
|
133
js/geometa.js
133
js/geometa.js
|
@ -1,5 +1,5 @@
|
|||
// A shim to implement the W3C Geolocation API Specification using Gears
|
||||
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) (function(){
|
||||
// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API
|
||||
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) { (function(){
|
||||
|
||||
// -- BEGIN GEARS_INIT
|
||||
(function() {
|
||||
|
@ -23,8 +23,7 @@ if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim )
|
|||
}
|
||||
} catch (e) {
|
||||
// Safari
|
||||
if ((typeof navigator.mimeTypes != 'undefined')
|
||||
&& navigator.mimeTypes["application/x-googlegears"]) {
|
||||
if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
|
||||
factory = document.createElement("object");
|
||||
factory.style.display = "none";
|
||||
factory.width = 0;
|
||||
|
@ -64,8 +63,8 @@ var GearsGeoLocation = (function() {
|
|||
return function(position) {
|
||||
callback(position);
|
||||
self.lastPosition = position;
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// -- PUBLIC
|
||||
return {
|
||||
|
@ -96,9 +95,123 @@ var GearsGeoLocation = (function() {
|
|||
};
|
||||
});
|
||||
|
||||
// If you have Gears installed use that
|
||||
if (window.google && google.gears) {
|
||||
navigator.geolocation = GearsGeoLocation();
|
||||
}
|
||||
var AjaxGeoLocation = (function() {
|
||||
// -- PRIVATE
|
||||
var loading = false;
|
||||
var loadGoogleLoader = function() {
|
||||
if (!hasGoogleLoader() && !loading) {
|
||||
loading = true;
|
||||
var s = document.createElement('script');
|
||||
s.src = (document.location.protocol == "https:"?"https://":"http://") + 'www.google.com/jsapi?callback=_google_loader_apiLoaded';
|
||||
s.type = "text/javascript";
|
||||
document.getElementsByTagName('body')[0].appendChild(s);
|
||||
}
|
||||
};
|
||||
|
||||
var queue = [];
|
||||
var addLocationQueue = function(callback) {
|
||||
queue.push(callback);
|
||||
};
|
||||
|
||||
var runLocationQueue = function() {
|
||||
if (hasGoogleLoader()) {
|
||||
while (queue.length > 0) {
|
||||
var call = queue.pop();
|
||||
call();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window['_google_loader_apiLoaded'] = function() {
|
||||
runLocationQueue();
|
||||
};
|
||||
|
||||
var hasGoogleLoader = function() {
|
||||
return (window['google'] && google['loader']);
|
||||
};
|
||||
|
||||
var checkGoogleLoader = function(callback) {
|
||||
if (hasGoogleLoader()) { return true; }
|
||||
|
||||
addLocationQueue(callback);
|
||||
|
||||
loadGoogleLoader();
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
loadGoogleLoader(); // start to load as soon as possible just in case
|
||||
|
||||
// -- PUBLIC
|
||||
return {
|
||||
shim: true,
|
||||
|
||||
type: "ClientLocation",
|
||||
|
||||
lastPosition: null,
|
||||
|
||||
getCurrentPosition: function(successCallback, errorCallback, options) {
|
||||
var self = this;
|
||||
if (!checkGoogleLoader(function() {
|
||||
self.getCurrentPosition(successCallback, errorCallback, options);
|
||||
})) { return; }
|
||||
|
||||
if (google.loader.ClientLocation) {
|
||||
var cl = google.loader.ClientLocation;
|
||||
|
||||
var position = {
|
||||
coords: {
|
||||
latitude: cl.latitude,
|
||||
longitude: cl.longitude,
|
||||
altitude: null,
|
||||
accuracy: 43000, // same as Gears accuracy over wifi?
|
||||
altitudeAccuracy: null,
|
||||
heading: null,
|
||||
speed: null
|
||||
},
|
||||
// extra info that is outside of the bounds of the core API
|
||||
address: {
|
||||
city: cl.address.city,
|
||||
country: cl.address.country,
|
||||
country_code: cl.address.country_code,
|
||||
region: cl.address.region
|
||||
},
|
||||
timestamp: new Date()
|
||||
};
|
||||
|
||||
successCallback(position);
|
||||
|
||||
this.lastPosition = position;
|
||||
} else if (errorCallback === "function") {
|
||||
errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."});
|
||||
}
|
||||
},
|
||||
|
||||
watchPosition: function(successCallback, errorCallback, options) {
|
||||
this.getCurrentPosition(successCallback, errorCallback, options);
|
||||
|
||||
var self = this;
|
||||
var watchId = setInterval(function() {
|
||||
self.getCurrentPosition(successCallback, errorCallback, options);
|
||||
}, 10000);
|
||||
|
||||
return watchId;
|
||||
},
|
||||
|
||||
clearWatch: function(watchId) {
|
||||
clearInterval(watchId);
|
||||
},
|
||||
|
||||
getPermission: function(siteName, imageUrl, extraMessage) {
|
||||
// for now just say yes :)
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
});
|
||||
|
||||
// If you have Gears installed use that, else use Ajax ClientLocation
|
||||
navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation() : AjaxGeoLocation();
|
||||
|
||||
})();
|
||||
}
|
||||
|
|
135
js/util.js
135
js/util.js
|
@ -289,6 +289,7 @@ var SN = { // StatusNet
|
|||
}
|
||||
}
|
||||
$('#'+form_id).resetForm();
|
||||
$('#'+form_id+' #'+SN.C.S.NoticeInReplyTo).val('');
|
||||
$('#'+form_id+' #'+SN.C.S.NoticeDataAttachSelected).remove();
|
||||
SN.U.FormNoticeEnhancements($('#'+form_id));
|
||||
}
|
||||
|
@ -480,8 +481,9 @@ var SN = { // StatusNet
|
|||
var NDGe = $('#'+SN.C.S.NoticeDataGeo);
|
||||
|
||||
function removeNoticeDataGeo() {
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']').removeClass('checked').attr('title', jQuery.trim($('label[for='+SN.C.S.NoticeDataGeo+']').text()));
|
||||
$('#'+SN.C.S.NoticeDataGeoSelected).hide();
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']')
|
||||
.attr('title', jQuery.trim($('label[for='+SN.C.S.NoticeDataGeo+']').text()))
|
||||
.removeClass('checked');
|
||||
|
||||
$('#'+SN.C.S.NoticeLat).val('');
|
||||
$('#'+SN.C.S.NoticeLon).val('');
|
||||
|
@ -492,7 +494,7 @@ var SN = { // StatusNet
|
|||
$.cookie(SN.C.S.NoticeDataGeoCookie, 'disabled');
|
||||
}
|
||||
|
||||
function getJSONgeocodeURL(geocodeURL, data) {
|
||||
function getJSONgeocodeURL(geocodeURL, data, position) {
|
||||
$.getJSON(geocodeURL, data, function(location) {
|
||||
var lns, lid;
|
||||
|
||||
|
@ -513,17 +515,8 @@ var SN = { // StatusNet
|
|||
NLN_text = location.name;
|
||||
}
|
||||
|
||||
$('#'+SN.C.S.NoticeGeoName)
|
||||
.replaceWith('<a id="notice_data-geo_name"/>');
|
||||
|
||||
$('#'+SN.C.S.NoticeGeoName)
|
||||
.attr('href', location.url)
|
||||
.text(NLN_text)
|
||||
.click(function() {
|
||||
window.open(location.url);
|
||||
|
||||
return false;
|
||||
});
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']')
|
||||
.attr('title', NoticeDataGeo_text.ShareDisable + ' (' + NLN_text + ')');
|
||||
|
||||
$('#'+SN.C.S.NoticeLat).val(data.lat);
|
||||
$('#'+SN.C.S.NoticeLon).val(data.lon);
|
||||
|
@ -532,14 +525,13 @@ var SN = { // StatusNet
|
|||
$('#'+SN.C.S.NoticeDataGeo).attr('checked', true);
|
||||
|
||||
var cookieValue = {
|
||||
'NLat': data.lat,
|
||||
'NLon': data.lon,
|
||||
'NLNS': lns,
|
||||
'NLID': lid,
|
||||
'NLN': NLN_text,
|
||||
'NLNU': location.url,
|
||||
'NDG': true,
|
||||
'NDGSM': false
|
||||
NLat: data.lat,
|
||||
NLon: data.lon,
|
||||
NLNS: lns,
|
||||
NLID: lid,
|
||||
NLN: NLN_text,
|
||||
NLNU: location.url,
|
||||
NDG: true
|
||||
};
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, JSON.stringify(cookieValue));
|
||||
});
|
||||
|
@ -557,62 +549,14 @@ var SN = { // StatusNet
|
|||
var geocodeURL = NGW.attr('title');
|
||||
NGW.removeAttr('title');
|
||||
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']').attr('title', jQuery.trim($('label[for='+SN.C.S.NoticeDataGeo+']').text()));
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']')
|
||||
.attr('title', jQuery.trim($('label[for='+SN.C.S.NoticeDataGeo+']').text()));
|
||||
|
||||
NDGe.change(function() {
|
||||
var NLN = $('#'+SN.C.S.NoticeGeoName);
|
||||
if (NLN.length > 0) {
|
||||
NLN.remove();
|
||||
}
|
||||
|
||||
if ($('#'+SN.C.S.NoticeDataGeo).attr('checked') === true || $.cookie(SN.C.S.NoticeDataGeoCookie) === null) {
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']').addClass('checked').attr('title', NoticeDataGeoShareDisable_text);
|
||||
|
||||
var S = '<div id="'+SN.C.S.NoticeDataGeoSelected+'" class="'+SN.C.S.Success+'"/>';
|
||||
var NDGS = $('#'+SN.C.S.NoticeDataGeoSelected);
|
||||
|
||||
if (NDGS.length > 0) {
|
||||
NDGS.replaceWith(S);
|
||||
}
|
||||
else {
|
||||
$('#'+SN.C.S.FormNotice).append(S);
|
||||
}
|
||||
|
||||
NDGS = $('#'+SN.C.S.NoticeDataGeoSelected);
|
||||
NDGS.prepend('<span id="'+SN.C.S.NoticeGeoName+'">Geo</span> <button class="minimize" title="'+NoticeDataGeoInfoMinimize_text+'">_</button> <button class="close" title="'+NoticeDataGeoShareDisable_text+'">×</button>');
|
||||
|
||||
var NLN = $('#'+SN.C.S.NoticeGeoName);
|
||||
NLN.addClass('processing');
|
||||
|
||||
$('#'+SN.C.S.NoticeDataGeoSelected+' button.close').click(function(){
|
||||
removeNoticeDataGeo();
|
||||
|
||||
$('#'+SN.C.S.NoticeDataGeoSelected).remove();
|
||||
|
||||
$('#'+SN.C.S.NoticeDataText).focus();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#'+SN.C.S.NoticeDataGeoSelected+' button.minimize').click(function(){
|
||||
$('#'+SN.C.S.NoticeDataGeoSelected).hide();
|
||||
|
||||
var cookieValue = {
|
||||
'NLat': $('#'+SN.C.S.NoticeLat).val(),
|
||||
'NLon': $('#'+SN.C.S.NoticeLat).val(),
|
||||
'NLNS': $('#'+SN.C.S.NoticeLocationNs).val(),
|
||||
'NLID': $('#'+SN.C.S.NoticeLocationId).val(),
|
||||
'NLN': $('#'+SN.C.S.NoticeGeoName).text(),
|
||||
'NLNU': $('#'+SN.C.S.NoticeGeoName).attr('href'),
|
||||
'NDG': true,
|
||||
'NDGSM': true
|
||||
};
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, JSON.stringify(cookieValue));
|
||||
|
||||
$('#'+SN.C.S.NoticeDataText).focus();
|
||||
|
||||
return false;
|
||||
});
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']')
|
||||
.attr('title', NoticeDataGeo_text.ShareDisable)
|
||||
.addClass('checked');
|
||||
|
||||
if ($.cookie(SN.C.S.NoticeDataGeoCookie) === null || $.cookie(SN.C.S.NoticeDataGeoCookie) == 'disabled') {
|
||||
if (navigator.geolocation) {
|
||||
|
@ -622,18 +566,27 @@ var SN = { // StatusNet
|
|||
$('#'+SN.C.S.NoticeLon).val(position.coords.longitude);
|
||||
|
||||
var data = {
|
||||
'lat': position.coords.latitude,
|
||||
'lon': position.coords.longitude,
|
||||
'token': $('#token').val()
|
||||
lat: position.coords.latitude,
|
||||
lon: position.coords.longitude,
|
||||
token: $('#token').val()
|
||||
};
|
||||
|
||||
getJSONgeocodeURL(geocodeURL, data);
|
||||
getJSONgeocodeURL(geocodeURL, data, position);
|
||||
},
|
||||
|
||||
function(error) {
|
||||
if (error.PERMISSION_DENIED == 1) {
|
||||
switch(error.code) {
|
||||
case error.PERMISSION_DENIED:
|
||||
removeNoticeDataGeo();
|
||||
break;
|
||||
case error.TIMEOUT:
|
||||
$('#'+SN.C.S.NoticeDataGeo).attr('checked', false);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
timeout: 10000
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -645,7 +598,7 @@ var SN = { // StatusNet
|
|||
'token': $('#token').val()
|
||||
};
|
||||
|
||||
getJSONgeocodeURL(geocodeURL, data);
|
||||
getJSONgeocodeURL(geocodeURL, data, position);
|
||||
}
|
||||
else {
|
||||
removeNoticeDataGeo();
|
||||
|
@ -657,34 +610,20 @@ var SN = { // StatusNet
|
|||
else {
|
||||
var cookieValue = JSON.parse($.cookie(SN.C.S.NoticeDataGeoCookie));
|
||||
|
||||
if (cookieValue.NDGSM === true) {
|
||||
$('#'+SN.C.S.NoticeDataGeoSelected).hide();
|
||||
}
|
||||
|
||||
$('#'+SN.C.S.NoticeLat).val(cookieValue.NLat);
|
||||
$('#'+SN.C.S.NoticeLon).val(cookieValue.NLon);
|
||||
$('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS);
|
||||
$('#'+SN.C.S.NoticeLocationId).val(cookieValue.NLID);
|
||||
$('#'+SN.C.S.NoticeDataGeo).attr('checked', cookieValue.NDG);
|
||||
|
||||
$('#'+SN.C.S.NoticeGeoName)
|
||||
.replaceWith('<a id="notice_data-geo_name"/>');
|
||||
|
||||
$('#'+SN.C.S.NoticeGeoName)
|
||||
.attr('href', cookieValue.NLNU)
|
||||
.text(cookieValue.NLN)
|
||||
.click(function() {
|
||||
window.open($(this).attr('href'));
|
||||
|
||||
return false;
|
||||
});
|
||||
$('label[for='+SN.C.S.NoticeDataGeo+']')
|
||||
.attr('title', NoticeDataGeo_text.ShareDisable + ' (' + cookieValue.NLN + ')')
|
||||
.addClass('checked');
|
||||
}
|
||||
}
|
||||
else {
|
||||
removeNoticeDataGeo();
|
||||
}
|
||||
|
||||
$('#'+SN.C.S.NoticeDataText).focus();
|
||||
}).change();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -141,7 +141,7 @@ class Action extends HTMLOutputter // lawsuit
|
|||
function showTitle()
|
||||
{
|
||||
$this->element('title', null,
|
||||
sprintf(_("%1$s - %2$s"),
|
||||
sprintf(_("%1\$s - %2\$s"),
|
||||
$this->title(),
|
||||
common_config('site', 'name')));
|
||||
}
|
||||
|
|
11
lib/api.php
11
lib/api.php
|
@ -53,6 +53,9 @@ if (!defined('STATUSNET')) {
|
|||
|
||||
class ApiAction extends Action
|
||||
{
|
||||
const READ_ONLY = 1;
|
||||
const READ_WRITE = 2;
|
||||
|
||||
var $format = null;
|
||||
var $user = null;
|
||||
var $auth_user = null;
|
||||
|
@ -62,6 +65,8 @@ class ApiAction extends Action
|
|||
var $since_id = null;
|
||||
var $since = null;
|
||||
|
||||
var $access = self::READ_ONLY; // read (default) or read-write
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
|
@ -140,12 +145,14 @@ class ApiAction extends Action
|
|||
|
||||
// Note: some profiles don't have an associated user
|
||||
|
||||
$defaultDesign = Design::siteDesign();
|
||||
|
||||
if (!empty($user)) {
|
||||
$design = $user->getDesign();
|
||||
}
|
||||
|
||||
if (empty($design)) {
|
||||
$design = Design::siteDesign();
|
||||
$design = $defaultDesign;
|
||||
}
|
||||
|
||||
$color = Design::toWebColor(empty($design->backgroundcolor) ? $defaultDesign->backgroundcolor : $design->backgroundcolor);
|
||||
|
@ -166,7 +173,7 @@ class ApiAction extends Action
|
|||
|
||||
$timezone = 'UTC';
|
||||
|
||||
if ($user->timezone) {
|
||||
if (!empty($user) && $user->timezone) {
|
||||
$timezone = $user->timezone;
|
||||
}
|
||||
|
||||
|
|
108
lib/apiauth.php
108
lib/apiauth.php
|
@ -39,6 +39,7 @@ if (!defined('STATUSNET')) {
|
|||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/api.php';
|
||||
require_once INSTALLDIR . '/lib/apioauth.php';
|
||||
|
||||
/**
|
||||
* Actions extending this class will require auth
|
||||
|
@ -52,6 +53,9 @@ require_once INSTALLDIR . '/lib/api.php';
|
|||
|
||||
class ApiAuthAction extends ApiAction
|
||||
{
|
||||
var $access_token;
|
||||
var $oauth_access_type;
|
||||
var $oauth_source;
|
||||
|
||||
/**
|
||||
* Take arguments for running, and output basic auth header if needed
|
||||
|
@ -67,12 +71,115 @@ class ApiAuthAction extends ApiAction
|
|||
parent::prepare($args);
|
||||
|
||||
if ($this->requiresAuth()) {
|
||||
|
||||
$this->consumer_key = $this->arg('oauth_consumer_key');
|
||||
$this->access_token = $this->arg('oauth_token');
|
||||
|
||||
if (!empty($this->access_token)) {
|
||||
$this->checkOAuthRequest();
|
||||
} else {
|
||||
$this->checkBasicAuthUser();
|
||||
// By default, all basic auth users have read and write access
|
||||
|
||||
$this->access = self::READ_WRITE;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
}
|
||||
|
||||
function checkOAuthRequest()
|
||||
{
|
||||
common_debug("We have an OAuth request.");
|
||||
|
||||
$datastore = new ApiStatusNetOAuthDataStore();
|
||||
$server = new OAuthServer($datastore);
|
||||
$hmac_method = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
|
||||
$server->add_signature_method($hmac_method);
|
||||
|
||||
ApiOauthAction::cleanRequest();
|
||||
|
||||
try {
|
||||
|
||||
$req = OAuthRequest::from_request();
|
||||
$server->verify_request($req);
|
||||
|
||||
$app = Oauth_application::getByConsumerKey($this->consumer_key);
|
||||
|
||||
if (empty($app)) {
|
||||
|
||||
// this should really not happen
|
||||
common_log(LOG_WARN,
|
||||
"Couldn't find the OAuth app for consumer key: $this->consumer_key");
|
||||
|
||||
throw new OAuthException('No application for that consumer key.');
|
||||
}
|
||||
|
||||
// set the source attr
|
||||
|
||||
$this->oauth_source = $app->name;
|
||||
|
||||
$appUser = Oauth_application_user::staticGet('token',
|
||||
$this->access_token);
|
||||
|
||||
// XXX: check that app->id and appUser->application_id and consumer all
|
||||
// match?
|
||||
|
||||
if (!empty($appUser)) {
|
||||
|
||||
// read or read-write
|
||||
$this->oauth_access_type = $appUser->access_type;
|
||||
|
||||
// If access_type == 0 we have either a request token
|
||||
// or a bad / revoked access token
|
||||
|
||||
if ($this->oauth_access_type != 0) {
|
||||
|
||||
// Set the read or read-write access for the api call
|
||||
$this->access = ($appUser->access_type & Oauth_application::$writeAccess)
|
||||
? self::READ_WRITE : self::READ_ONLY;
|
||||
|
||||
$this->auth_user = User::staticGet('id', $appUser->profile_id);
|
||||
|
||||
$msg = "API OAuth authentication for user '%s' (id: %d) on behalf of " .
|
||||
"application '%s' (id: %d).";
|
||||
|
||||
common_log(LOG_INFO, sprintf($msg,
|
||||
$this->auth_user->nickname,
|
||||
$this->auth_user->id,
|
||||
$app->name,
|
||||
$app->id));
|
||||
return true;
|
||||
} else {
|
||||
throw new OAuthException('Bad access token.');
|
||||
}
|
||||
} else {
|
||||
|
||||
// also should not happen
|
||||
throw new OAuthException('No user for that token.');
|
||||
}
|
||||
|
||||
} catch (OAuthException $e) {
|
||||
common_log(LOG_WARN, 'API OAuthException - ' . $e->getMessage());
|
||||
common_debug(var_export($req, true));
|
||||
$this->showOAuthError($e->getMessage());
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
function showOAuthError($msg)
|
||||
{
|
||||
header('HTTP/1.1 401 Unauthorized');
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
print $msg . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this API resource require authentication?
|
||||
*
|
||||
|
@ -128,6 +235,7 @@ class ApiAuthAction extends ApiAction
|
|||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
122
lib/apioauth.php
Normal file
122
lib/apioauth.php
Normal file
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Base action for OAuth API endpoints
|
||||
*
|
||||
* 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 Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/lib/apioauthstore.php';
|
||||
|
||||
/**
|
||||
* Base action for API OAuth enpoints. Clean up the
|
||||
* the request, and possibly some other common things
|
||||
* here.
|
||||
*
|
||||
* @category API
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApiOauthAction extends Action
|
||||
{
|
||||
/**
|
||||
* Is this a read-only action?
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle input, produce output
|
||||
*
|
||||
* Switches on request method; either shows the form or handles its input.
|
||||
*
|
||||
* @param array $args $_REQUEST data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
self::cleanRequest();
|
||||
}
|
||||
|
||||
static function cleanRequest()
|
||||
{
|
||||
// kill evil effects of magical slashing
|
||||
|
||||
if (get_magic_quotes_gpc() == 1) {
|
||||
$_POST = array_map('stripslashes', $_POST);
|
||||
$_GET = array_map('stripslashes', $_GET);
|
||||
}
|
||||
|
||||
// strip out the p param added in index.php
|
||||
|
||||
// XXX: should we strip anything else? Or alternatively
|
||||
// only allow a known list of params?
|
||||
|
||||
unset($_GET['p']);
|
||||
unset($_POST['p']);
|
||||
}
|
||||
|
||||
function getCallback($url, $params)
|
||||
{
|
||||
foreach ($params as $k => $v) {
|
||||
$url = $this->appendQueryVar($url,
|
||||
OAuthUtil::urlencode_rfc3986($k),
|
||||
OAuthUtil::urlencode_rfc3986($v));
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
function appendQueryVar($url, $k, $v) {
|
||||
$url = preg_replace('/(.*)(\?|&)' . $k . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
|
||||
$url = substr($url, 0, -1);
|
||||
if (strpos($url, '?') === false) {
|
||||
return ($url . '?' . $k . '=' . $v);
|
||||
} else {
|
||||
return ($url . '&' . $k . '=' . $v);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
163
lib/apioauthstore.php
Normal file
163
lib/apioauthstore.php
Normal file
|
@ -0,0 +1,163 @@
|
|||
<?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/oauthstore.php';
|
||||
|
||||
class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
|
||||
{
|
||||
|
||||
function lookup_consumer($consumer_key)
|
||||
{
|
||||
$con = Consumer::staticGet('consumer_key', $consumer_key);
|
||||
|
||||
if (!$con) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new OAuthConsumer($con->consumer_key,
|
||||
$con->consumer_secret);
|
||||
}
|
||||
|
||||
function getAppByRequestToken($token_key)
|
||||
{
|
||||
// Look up the full req tokenx
|
||||
|
||||
$req_token = $this->lookup_token(null,
|
||||
'request',
|
||||
$token_key);
|
||||
|
||||
if (empty($req_token)) {
|
||||
common_debug("couldn't get request token from oauth datastore");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look up the full Token
|
||||
|
||||
$token = new Token();
|
||||
$token->tok = $req_token->key;
|
||||
$result = $token->find(true);
|
||||
|
||||
if (empty($result)) {
|
||||
common_debug('Couldn\'t find req token in the token table.');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Look up the app
|
||||
|
||||
$app = new Oauth_application();
|
||||
$app->consumer_key = $token->consumer_key;
|
||||
$result = $app->find(true);
|
||||
|
||||
if (!empty($result)) {
|
||||
return $app;
|
||||
} else {
|
||||
common_debug("Couldn't find the app!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function new_access_token($token, $consumer)
|
||||
{
|
||||
common_debug('new_access_token("'.$token->key.'","'.$consumer->key.'")', __FILE__);
|
||||
|
||||
$rt = new Token();
|
||||
$rt->consumer_key = $consumer->key;
|
||||
$rt->tok = $token->key;
|
||||
$rt->type = 0; // request
|
||||
|
||||
$app = Oauth_application::getByConsumerKey($consumer->key);
|
||||
|
||||
if (empty($app)) {
|
||||
common_debug("empty app!");
|
||||
}
|
||||
|
||||
if ($rt->find(true) && $rt->state == 1) { // authorized
|
||||
common_debug('request token found.', __FILE__);
|
||||
|
||||
// find the associated user of the app
|
||||
|
||||
$appUser = new Oauth_application_user();
|
||||
$appUser->application_id = $app->id;
|
||||
$appUser->token = $rt->tok;
|
||||
$result = $appUser->find(true);
|
||||
|
||||
if (!empty($result)) {
|
||||
common_debug("Oath app user found.");
|
||||
} else {
|
||||
common_debug("Oauth app user not found. app id $app->id token $rt->tok");
|
||||
return null;
|
||||
}
|
||||
|
||||
// go ahead and make the access token
|
||||
|
||||
$at = new Token();
|
||||
$at->consumer_key = $consumer->key;
|
||||
$at->tok = common_good_rand(16);
|
||||
$at->secret = common_good_rand(16);
|
||||
$at->type = 1; // access
|
||||
$at->created = DB_DataObject_Cast::dateTime();
|
||||
|
||||
if (!$at->insert()) {
|
||||
$e = $at->_lastError;
|
||||
common_debug('access token "'.$at->tok.'" not inserted: "'.$e->message.'"', __FILE__);
|
||||
return null;
|
||||
} else {
|
||||
common_debug('access token "'.$at->tok.'" inserted', __FILE__);
|
||||
// burn the old one
|
||||
$orig_rt = clone($rt);
|
||||
$rt->state = 2; // used
|
||||
if (!$rt->update($orig_rt)) {
|
||||
return null;
|
||||
}
|
||||
common_debug('request token "'.$rt->tok.'" updated', __FILE__);
|
||||
|
||||
// update the token from req to access for the user
|
||||
|
||||
$orig = clone($appUser);
|
||||
$appUser->token = $at->tok;
|
||||
|
||||
// It's at this point that we change the access type
|
||||
// to whatever the application's access is. Request
|
||||
// tokens should always have an access type of 0, and
|
||||
// therefore be unuseable for making requests for
|
||||
// protected resources.
|
||||
|
||||
$appUser->access_type = $app->access_type;
|
||||
|
||||
$result = $appUser->update($orig);
|
||||
|
||||
if (empty($result)) {
|
||||
common_debug('couldn\'t update OAuth app user.');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Okay, good
|
||||
|
||||
return new OAuthToken($at->tok, $at->secret);
|
||||
}
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
338
lib/applicationeditform.php
Normal file
338
lib/applicationeditform.php
Normal file
|
@ -0,0 +1,338 @@
|
|||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Form for editing an application
|
||||
*
|
||||
* 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 Form
|
||||
* @package StatusNet
|
||||
* @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/form.php';
|
||||
|
||||
/**
|
||||
* Form for editing an application
|
||||
*
|
||||
* @category Form
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
*/
|
||||
|
||||
class ApplicationEditForm extends Form
|
||||
{
|
||||
/**
|
||||
* group for user to join
|
||||
*/
|
||||
|
||||
var $application = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Action $out output channel
|
||||
* @param User_group $group group to join
|
||||
*/
|
||||
|
||||
function __construct($out=null, $application=null)
|
||||
{
|
||||
parent::__construct($out);
|
||||
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the form
|
||||
*
|
||||
* @return string ID of the form
|
||||
*/
|
||||
|
||||
function id()
|
||||
{
|
||||
if ($this->application) {
|
||||
return 'form_application_edit-' . $this->application->id;
|
||||
} else {
|
||||
return 'form_application_add';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP method used to submit the form
|
||||
*
|
||||
* For image data we need to send multipart/form-data
|
||||
* so we set that here too
|
||||
*
|
||||
* @return string the method to use for submitting
|
||||
*/
|
||||
|
||||
function method()
|
||||
{
|
||||
$this->enctype = 'multipart/form-data';
|
||||
return 'post';
|
||||
}
|
||||
|
||||
/**
|
||||
* class of the form
|
||||
*
|
||||
* @return string of the form class
|
||||
*/
|
||||
|
||||
function formClass()
|
||||
{
|
||||
return 'form_settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Action of the form
|
||||
*
|
||||
* @return string URL of the action
|
||||
*/
|
||||
|
||||
function action()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
|
||||
if (!empty($this->application)) {
|
||||
return common_local_url('editapplication',
|
||||
array('id' => $this->application->id));
|
||||
} else {
|
||||
return common_local_url('newapplication');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formLegend()
|
||||
{
|
||||
$this->out->element('legend', null, _('Edit application'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data elements of the form
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formData()
|
||||
{
|
||||
if ($this->application) {
|
||||
$id = $this->application->id;
|
||||
$icon = $this->application->icon;
|
||||
$name = $this->application->name;
|
||||
$description = $this->application->description;
|
||||
$source_url = $this->application->source_url;
|
||||
$organization = $this->application->organization;
|
||||
$homepage = $this->application->homepage;
|
||||
$callback_url = $this->application->callback_url;
|
||||
$this->type = $this->application->type;
|
||||
$this->access_type = $this->application->access_type;
|
||||
} else {
|
||||
$id = '';
|
||||
$icon = '';
|
||||
$name = '';
|
||||
$description = '';
|
||||
$source_url = '';
|
||||
$organization = '';
|
||||
$homepage = '';
|
||||
$callback_url = '';
|
||||
$this->type = '';
|
||||
$this->access_type = '';
|
||||
}
|
||||
|
||||
$this->out->hidden('token', common_session_token());
|
||||
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
|
||||
$this->out->elementStart('li', array('id' => 'application_icon'));
|
||||
|
||||
if (!empty($icon)) {
|
||||
$this->out->element('img', array('src' => $icon));
|
||||
}
|
||||
|
||||
$this->out->element('label', array('for' => 'app_icon'),
|
||||
_('Icon'));
|
||||
$this->out->element('input', array('name' => 'app_icon',
|
||||
'type' => 'file',
|
||||
'id' => 'app_icon'));
|
||||
$this->out->element('p', 'form_guide', _('Icon for this application'));
|
||||
$this->out->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||
'type' => 'hidden',
|
||||
'id' => 'MAX_FILE_SIZE',
|
||||
'value' => ImageFile::maxFileSizeInt()));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
|
||||
$this->out->hidden('application_id', $id);
|
||||
|
||||
$this->out->input('name', _('Name'),
|
||||
($this->out->arg('name')) ? $this->out->arg('name') : $name);
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
|
||||
$maxDesc = Oauth_application::maxDesc();
|
||||
if ($maxDesc > 0) {
|
||||
$descInstr = sprintf(_('Describe your application in %d characters'),
|
||||
$maxDesc);
|
||||
} else {
|
||||
$descInstr = _('Describe your application');
|
||||
}
|
||||
$this->out->textarea('description', _('Description'),
|
||||
($this->out->arg('description')) ? $this->out->arg('description') : $description,
|
||||
$descInstr);
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('source_url', _('Source URL'),
|
||||
($this->out->arg('source_url')) ? $this->out->arg('source_url') : $source_url,
|
||||
_('URL of the homepage of this application'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('organization', _('Organization'),
|
||||
($this->out->arg('organization')) ? $this->out->arg('organization') : $organization,
|
||||
_('Organization responsible for this application'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('homepage', _('Homepage'),
|
||||
($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
|
||||
_('URL for the homepage of the organization'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('callback_url', ('Callback URL'),
|
||||
($this->out->arg('callback_url')) ? $this->out->arg('callback_url') : $callback_url,
|
||||
_('URL to redirect to after authentication'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li', array('id' => 'application_types'));
|
||||
|
||||
$attrs = array('name' => 'app_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'app_type-browser',
|
||||
'class' => 'radio',
|
||||
'value' => Oauth_application::$browser);
|
||||
|
||||
// Default to Browser
|
||||
|
||||
if ($this->application->type == Oauth_application::$browser
|
||||
|| empty($this->application->type)) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'app_type-browser',
|
||||
'class' => 'radio'),
|
||||
_('Browser'));
|
||||
|
||||
$attrs = array('name' => 'app_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'app_type-dekstop',
|
||||
'class' => 'radio',
|
||||
'value' => Oauth_application::$desktop);
|
||||
|
||||
if ($this->application->type == Oauth_application::$desktop) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'app_type-desktop',
|
||||
'class' => 'radio'),
|
||||
_('Desktop'));
|
||||
$this->out->element('p', 'form_guide', _('Type of application, browser or desktop'));
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li', array('id' => 'default_access_types'));
|
||||
|
||||
$attrs = array('name' => 'default_access_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'default_access_type-r',
|
||||
'class' => 'radio',
|
||||
'value' => 'r');
|
||||
|
||||
// default to read-only access
|
||||
|
||||
if ($this->application->access_type & Oauth_application::$readAccess
|
||||
|| empty($this->application->access_type)) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'default_access_type-ro',
|
||||
'class' => 'radio'),
|
||||
_('Read-only'));
|
||||
|
||||
$attrs = array('name' => 'default_access_type',
|
||||
'type' => 'radio',
|
||||
'id' => 'default_access_type-rw',
|
||||
'class' => 'radio',
|
||||
'value' => 'rw');
|
||||
|
||||
if ($this->application->access_type & Oauth_application::$readAccess
|
||||
&& $this->application->access_type & Oauth_application::$writeAccess
|
||||
) {
|
||||
$attrs['checked'] = 'checked';
|
||||
}
|
||||
|
||||
$this->out->element('input', $attrs);
|
||||
|
||||
$this->out->element('label', array('for' => 'default_access_type-rw',
|
||||
'class' => 'radio'),
|
||||
_('Read-write'));
|
||||
$this->out->element('p', 'form_guide', _('Default access for this application: read-only, or read-write'));
|
||||
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
|
||||
/**
|
||||
* Action elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function formActions()
|
||||
{
|
||||
$this->out->submit('cancel', _('Cancel'), 'submit form_action-primary',
|
||||
'cancel', _('Cancel'));
|
||||
$this->out->submit('save', _('Save'), 'submit form_action-secondary',
|
||||
'save', _('Save'));
|
||||
}
|
||||
}
|
168
lib/applicationlist.php
Normal file
168
lib/applicationlist.php
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* Widget to show a list of OAuth applications
|
||||
*
|
||||
* 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 Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@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/widget.php';
|
||||
|
||||
define('APPS_PER_PAGE', 20);
|
||||
|
||||
/**
|
||||
* Widget to show a list of OAuth applications
|
||||
*
|
||||
* @category Application
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
class ApplicationList extends Widget
|
||||
{
|
||||
/** Current application, application query */
|
||||
var $application = null;
|
||||
|
||||
/** Owner of this list */
|
||||
var $owner = null;
|
||||
|
||||
/** Action object using us. */
|
||||
var $action = null;
|
||||
|
||||
function __construct($application, $owner=null, $action=null, $connections = false)
|
||||
{
|
||||
parent::__construct($action);
|
||||
|
||||
$this->application = $application;
|
||||
$this->owner = $owner;
|
||||
$this->action = $action;
|
||||
$this->connections = $connections;
|
||||
}
|
||||
|
||||
function show()
|
||||
{
|
||||
$this->out->elementStart('ul', 'applications');
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
while ($this->application->fetch()) {
|
||||
$cnt++;
|
||||
if($cnt > APPS_PER_PAGE) {
|
||||
break;
|
||||
}
|
||||
$this->showapplication();
|
||||
}
|
||||
|
||||
$this->out->elementEnd('ul');
|
||||
|
||||
return $cnt;
|
||||
}
|
||||
|
||||
function showApplication()
|
||||
{
|
||||
|
||||
$user = common_current_user();
|
||||
|
||||
$this->out->elementStart('li', array('class' => 'application',
|
||||
'id' => 'oauthclient-' . $this->application->id));
|
||||
|
||||
$this->out->elementStart('span', 'vcard author');
|
||||
if (!$this->connections) {
|
||||
$this->out->elementStart('a',
|
||||
array('href' => common_local_url('showapplication',
|
||||
array('id' => $this->application->id)),
|
||||
'class' => 'url'));
|
||||
|
||||
} else {
|
||||
$this->out->elementStart('a', array('href' => $this->application->source_url,
|
||||
'class' => 'url'));
|
||||
}
|
||||
|
||||
if (!empty($this->application->icon)) {
|
||||
$this->out->element('img', array('src' => $this->application->icon,
|
||||
'class' => 'photo avatar'));
|
||||
}
|
||||
|
||||
$this->out->element('span', 'fn', $this->application->name);
|
||||
$this->out->elementEnd('a');
|
||||
$this->out->elementEnd('span');
|
||||
|
||||
$this->out->raw(' by ');
|
||||
|
||||
$this->out->element('a', array('href' => $this->application->homepage,
|
||||
'class' => 'url'),
|
||||
$this->application->organization);
|
||||
|
||||
$this->out->element('p', 'note', $this->application->description);
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
if ($this->connections) {
|
||||
$appUser = Oauth_application_user::getByKeys($this->owner, $this->application);
|
||||
|
||||
if (empty($appUser)) {
|
||||
common_debug("empty appUser!");
|
||||
}
|
||||
|
||||
$this->out->elementStart('li');
|
||||
|
||||
$access = ($this->application->access_type & Oauth_application::$writeAccess)
|
||||
? 'read-write' : 'read-only';
|
||||
|
||||
$txt = 'Approved ' . common_date_string($appUser->modified) .
|
||||
" - $access access.";
|
||||
|
||||
$this->out->raw($txt);
|
||||
$this->out->elementEnd('li');
|
||||
|
||||
$this->out->elementStart('li', 'entity_revoke');
|
||||
$this->out->elementStart('form', array('id' => 'form_revoke_app',
|
||||
'class' => 'form_revoke_app',
|
||||
'method' => 'POST',
|
||||
'action' =>
|
||||
common_local_url('oauthconnectionssettings')));
|
||||
$this->out->elementStart('fieldset');
|
||||
$this->out->hidden('id', $this->application->id);
|
||||
$this->out->hidden('token', common_session_token());
|
||||
$this->out->submit('revoke', _('Revoke'));
|
||||
$this->out->elementEnd('fieldset');
|
||||
$this->out->elementEnd('form');
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
}
|
||||
|
||||
/* Override this in subclasses. */
|
||||
|
||||
function showOwnerControls()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user