Merge branch 'testing' of git@gitorious.org:statusnet/mainline into testing

This commit is contained in:
Evan Prodromou 2010-02-03 12:32:48 -05:00
commit 900cb8dd91
30 changed files with 533 additions and 82 deletions

View File

@ -67,8 +67,6 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
{ {
parent::prepare($args); parent::prepare($args);
common_debug("apioauthauthorize");
$this->nickname = $this->trimmed('nickname'); $this->nickname = $this->trimmed('nickname');
$this->password = $this->arg('password'); $this->password = $this->arg('password');
$this->oauth_token = $this->arg('oauth_token'); $this->oauth_token = $this->arg('oauth_token');
@ -99,24 +97,17 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
} else { } else {
// XXX: make better error messages
if (empty($this->oauth_token)) { if (empty($this->oauth_token)) {
$this->clientError(_('No oauth_token parameter provided.'));
common_debug("No request token found.");
$this->clientError(_('Bad request.'));
return; return;
} }
if (empty($this->app)) { if (empty($this->app)) {
common_debug('No app for that token.'); $this->clientError(_('Invalid token.'));
$this->clientError(_('Bad request.'));
return; return;
} }
$name = $this->app->name; $name = $this->app->name;
common_debug("Requesting auth for app: " . $name);
$this->showForm(); $this->showForm();
} }
@ -124,8 +115,6 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
function handlePost() function handlePost()
{ {
common_debug("handlePost()");
// check session token for CSRF protection. // check session token for CSRF protection.
$token = $this->trimmed('token'); $token = $this->trimmed('token');
@ -202,21 +191,15 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
// A callback specified in the app setup overrides whatever // A callback specified in the app setup overrides whatever
// is passed in with the request. // is passed in with the request.
common_debug("Req token is authorized - doing callback");
if (!empty($this->app->callback_url)) { if (!empty($this->app->callback_url)) {
$this->callback = $this->app->callback_url; $this->callback = $this->app->callback_url;
} }
if (!empty($this->callback)) { if (!empty($this->callback)) {
// XXX: Need better way to build this redirect url.
$target_url = $this->getCallback($this->callback, $target_url = $this->getCallback($this->callback,
array('oauth_token' => $this->oauth_token)); array('oauth_token' => $this->oauth_token));
common_debug("Doing callback to $target_url");
common_redirect($target_url, 303); common_redirect($target_url, 303);
} else { } else {
common_debug("callback was empty!"); common_debug("callback was empty!");
@ -236,9 +219,12 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
} else if ($this->arg('deny')) { } else if ($this->arg('deny')) {
$datastore = new ApiStatusNetOAuthDataStore();
$datastore->revoke_token($this->oauth_token, 0);
$this->elementStart('p'); $this->elementStart('p');
$this->raw(sprintf(_("The request token %s has been denied."), $this->raw(sprintf(_("The request token %s has been denied and revoked."),
$this->oauth_token)); $this->oauth_token));
$this->elementEnd('p'); $this->elementEnd('p');
@ -305,12 +291,15 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$msg = _('The application <strong>%1$s</strong> by ' . $msg = _('The application <strong>%1$s</strong> by ' .
'<strong>%2$s</strong> would like the ability ' . '<strong>%2$s</strong> would like the ability ' .
'to <strong>%3$s</strong> your account data.'); 'to <strong>%3$s</strong> your %4$s account data. ' .
'You should only give access to your %4$s account ' .
'to third parties you trust.');
$this->raw(sprintf($msg, $this->raw(sprintf($msg,
$this->app->name, $this->app->name,
$this->app->organization, $this->app->organization,
$access)); $access,
common_config('site', 'name')));
$this->elementEnd('p'); $this->elementEnd('p');
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
@ -372,6 +361,31 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
function showLocalNav() function showLocalNav()
{ {
// NOP
}
/**
* Show site notice.
*
* @return nothing
*/
function showSiteNotice()
{
// NOP
}
/**
* Show notice form.
*
* Show the form for posting a new notice
*
* @return nothing
*/
function showNoticeForm()
{
// NOP
} }
} }

View File

@ -0,0 +1,176 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Action class to delete 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 Action
* @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') && !defined('LACONICA')) {
exit(1);
}
/**
* Delete an OAuth appliction
*
* @category Action
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*/
class DeleteapplicationAction extends Action
{
var $app = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
if (!parent::prepare($args)) {
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to delete an application.'));
return false;
}
$id = (int)$this->arg('id');
$this->app = Oauth_application::staticGet('id', $id);
if (empty($this->app)) {
$this->clientError(_('Application not found.'));
return false;
}
$cur = common_current_user();
if ($cur->id != $this->app->owner) {
$this->clientError(_('You are not the owner of this application.'), 401);
return false;
}
return true;
}
/**
* Handle request
*
* Shows a page with list of favorite notices
*
* @param array $args $_REQUEST args; handled in prepare()
*
* @return void
*/
function 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('no')) {
common_redirect(common_local_url('showapplication',
array('id' => $this->app->id)), 303);
} elseif ($this->arg('yes')) {
$this->handlePost();
common_redirect(common_local_url('oauthappssettings'), 303);
} else {
$this->showPage();
}
}
}
function showContent() {
$this->areYouSureForm();
}
function title() {
return _('Delete application');
}
function showNoticeForm() {
// nop
}
/**
* Confirm with user.
*
* Shows a confirmation form.
*
* @return void
*/
function areYouSureForm()
{
$id = $this->app->id;
$this->elementStart('form', array('id' => 'deleteapplication-' . $id,
'method' => 'post',
'class' => 'form_settings form_entity_block',
'action' => common_local_url('deleteapplication',
array('id' => $this->app->id))));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->element('legend', _('Delete application'));
$this->element('p', null,
_('Are you sure you want to delete this application? '.
'This will clear all data about the application from the '.
'database, including all existing user connections.'));
$this->submit('form_action-no',
_('No'),
'submit form_action-primary',
'no',
_("Do not delete this application"));
$this->submit('form_action-yes',
_('Yes'),
'submit form_action-secondary',
'yes', _('Delete this application'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
/**
* Actually delete the app
*
* @return void
*/
function handlePost()
{
$this->app->delete();
}
}

View File

@ -179,6 +179,9 @@ class EditApplicationAction extends OwnerDesignAction
} elseif (mb_strlen($name) > 255) { } elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).')); $this->showForm(_('Name is too long (max 255 chars).'));
return; return;
} else if ($this->nameExists($name)) {
$this->showForm(_('Name already in use. Try another one.'));
return;
} elseif (empty($description)) { } elseif (empty($description)) {
$this->showForm(_('Description is required.')); $this->showForm(_('Description is required.'));
return; return;
@ -260,5 +263,26 @@ class EditApplicationAction extends OwnerDesignAction
common_redirect(common_local_url('oauthappssettings'), 303); common_redirect(common_local_url('oauthappssettings'), 303);
} }
/**
* Does the app name already exist?
*
* Checks the DB to see someone has already registered an app
* with the same name.
*
* @param string $name app name to check
*
* @return boolean true if the name already exists
*/
function nameExists($name)
{
$newapp = Oauth_application::staticGet('name', $name);
if (!$newapp) {
return false;
} else {
return $newapp->id != $this->app->id;
}
}
} }

View File

@ -158,6 +158,9 @@ class NewApplicationAction extends OwnerDesignAction
if (empty($name)) { if (empty($name)) {
$this->showForm(_('Name is required.')); $this->showForm(_('Name is required.'));
return; return;
} else if ($this->nameExists($name)) {
$this->showForm(_('Name already in use. Try another one.'));
return;
} elseif (mb_strlen($name) > 255) { } elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).')); $this->showForm(_('Name is too long (max 255 chars).'));
return; return;
@ -273,5 +276,22 @@ class NewApplicationAction extends OwnerDesignAction
} }
/**
* Does the app name already exist?
*
* Checks the DB to see someone has already registered an app
* with the same name.
*
* @param string $name app name to check
*
* @return boolean true if the name already exists
*/
function nameExists($name)
{
$app = Oauth_application::staticGet('name', $name);
return ($app !== false);
}
} }

View File

@ -33,6 +33,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
require_once INSTALLDIR . '/lib/connectsettingsaction.php'; require_once INSTALLDIR . '/lib/connectsettingsaction.php';
require_once INSTALLDIR . '/lib/applicationlist.php'; require_once INSTALLDIR . '/lib/applicationlist.php';
require_once INSTALLDIR . '/lib/apioauthstore.php';
/** /**
* Show connected OAuth applications * Show connected OAuth applications
@ -71,11 +72,6 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
return _('Connected applications'); return _('Connected applications');
} }
function isReadOnly($args)
{
return true;
}
/** /**
* Instructions for use * Instructions for use
* *
@ -153,6 +149,13 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
} }
} }
/**
* Revoke access to an authorized OAuth application
*
* @param int $appId the ID of the application
*
*/
function revokeAccess($appId) function revokeAccess($appId)
{ {
$cur = common_current_user(); $cur = common_current_user();
@ -164,6 +167,8 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
return false; return false;
} }
// XXX: Transaction here?
$appUser = Oauth_application_user::getByKeys($cur, $app); $appUser = Oauth_application_user::getByKeys($cur, $app);
if (empty($appUser)) { if (empty($appUser)) {
@ -171,12 +176,13 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
return false; return false;
} }
$orig = clone($appUser); $datastore = new ApiStatusNetOAuthDataStore();
$appUser->access_type = 0; // No access $datastore->revoke_token($appUser->token, 1);
$result = $appUser->update();
$result = $appUser->delete();
if (!$result) { if (!$result) {
common_log_db_error($orig, 'UPDATE', __FILE__); common_log_db_error($orig, 'DELETE', __FILE__);
$this->clientError(_('Unable to revoke access for app: ' . $app->id)); $this->clientError(_('Unable to revoke access for app: ' . $app->id));
return false; return false;
} }

View File

@ -303,6 +303,27 @@ class RegisterAction extends Action
return ($user !== false); return ($user !== false);
} }
// overrrided to add entry-title class
function showPageTitle() {
if (Event::handle('StartShowPageTitle', array($this))) {
$this->element('h1', array('class' => 'entry-title'), $this->title());
}
}
// overrided to add hentry, and content-inner class
function showContentBlock()
{
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
$this->showPageTitle();
$this->showPageNoticeBlock();
$this->elementStart('div', array('id' => 'content_inner',
'class' => 'entry-content'));
// show the actual content (forms, lists, whatever)
$this->showContent();
$this->elementEnd('div');
$this->elementEnd('div');
}
/** /**
* Instructions or a notice for the page * Instructions or a notice for the page
* *

View File

@ -149,7 +149,6 @@ class ShowApplicationAction extends OwnerDesignAction
function showContent() function showContent()
{ {
$cur = common_current_user(); $cur = common_current_user();
$consumer = $this->application->getConsumer(); $consumer = $this->application->getConsumer();
@ -201,7 +200,7 @@ class ShowApplicationAction extends OwnerDesignAction
$userCnt = $appUsers->count(); $userCnt = $appUsers->count();
$this->raw(sprintf( $this->raw(sprintf(
_('created by %1$s - %2$s access by default - %3$d users'), _('Created by %1$s - %2$s access by default - %3$d users'),
$profile->getBestName(), $profile->getBestName(),
$defaultAccess, $defaultAccess,
$userCnt $userCnt
@ -222,18 +221,39 @@ class ShowApplicationAction extends OwnerDesignAction
$this->elementStart('li', 'entity_reset_keysecret'); $this->elementStart('li', 'entity_reset_keysecret');
$this->elementStart('form', array( $this->elementStart('form', array(
'id' => 'forma_reset_key', 'id' => 'form_reset_key',
'class' => 'form_reset_key', 'class' => 'form_reset_key',
'method' => 'POST', 'method' => 'POST',
'action' => common_local_url('showapplication', 'action' => common_local_url('showapplication',
array('id' => $this->application->id)))); array('id' => $this->application->id))));
$this->elementStart('fieldset'); $this->elementStart('fieldset');
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->submit('reset', _('Reset key & secret'));
$this->element('input', array('type' => 'submit',
'id' => 'reset',
'name' => 'reset',
'class' => 'submit',
'value' => _('Reset key & secret'),
'onClick' => 'return confirmReset()'));
$this->elementEnd('fieldset'); $this->elementEnd('fieldset');
$this->elementEnd('form'); $this->elementEnd('form');
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li', 'entity_delete');
$this->elementStart('form', array(
'id' => 'form_delete_application',
'class' => 'form_delete_application',
'method' => 'POST',
'action' => common_local_url('deleteapplication',
array('id' => $this->application->id))));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->submit('delete', _('Delete'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
$this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->elementEnd('div'); $this->elementEnd('div');
@ -276,14 +296,53 @@ class ShowApplicationAction extends OwnerDesignAction
$this->elementEnd('p'); $this->elementEnd('p');
} }
/**
* Add a confirm script for Consumer key/secret reset
*
* @return void
*/
function showScripts()
{
parent::showScripts();
$msg = _('Are you sure you want to reset your consumer key and secret?');
$js = 'function confirmReset() { ';
$js .= ' var agree = confirm("' . $msg . '"); ';
$js .= ' return agree;';
$js .= '}';
$this->inlineScript($js);
}
/**
* Reset an application's Consumer key and secret
*
* XXX: Should this be moved to its own page with a confirm?
*
*/
function resetKey() function resetKey()
{ {
$this->application->query('BEGIN'); $this->application->query('BEGIN');
$oauser = new Oauth_application_user();
$oauser->application_id = $this->application->id;
$result = $oauser->delete();
if ($result === false) {
common_log_db_error($oauser, 'DELETE', __FILE__);
$this->success = false;
$this->msg = ('Unable to reset consumer key and secret.');
$this->showPage();
return;
}
$consumer = $this->application->getConsumer(); $consumer = $this->application->getConsumer();
$result = $consumer->delete(); $result = $consumer->delete();
if (!$result) { if ($result === false) {
common_log_db_error($consumer, 'DELETE', __FILE__); common_log_db_error($consumer, 'DELETE', __FILE__);
$this->success = false; $this->success = false;
$this->msg = ('Unable to reset consumer key and secret.'); $this->msg = ('Unable to reset consumer key and secret.');
@ -295,7 +354,7 @@ class ShowApplicationAction extends OwnerDesignAction
$result = $consumer->insert(); $result = $consumer->insert();
if (!$result) { if (empty($result)) {
common_log_db_error($consumer, 'INSERT', __FILE__); common_log_db_error($consumer, 'INSERT', __FILE__);
$this->application->query('ROLLBACK'); $this->application->query('ROLLBACK');
$this->success = false; $this->success = false;
@ -308,7 +367,7 @@ class ShowApplicationAction extends OwnerDesignAction
$this->application->consumer_key = $consumer->consumer_key; $this->application->consumer_key = $consumer->consumer_key;
$result = $this->application->update($orig); $result = $this->application->update($orig);
if (!$result) { if ($result === false) {
common_log_db_error($application, 'UPDATE', __FILE__); common_log_db_error($application, 'UPDATE', __FILE__);
$this->application->query('ROLLBACK'); $this->application->query('ROLLBACK');
$this->success = false; $this->success = false;

View File

@ -36,4 +36,34 @@ class Consumer extends Memcached_DataObject
return $cons; return $cons;
} }
/**
* Delete a Consumer and related tokens and nonces
*
* XXX: Should this happen in an OAuthDataStore instead?
*
*/
function delete()
{
// XXX: Is there any reason NOT to do this kind of cleanup?
$this->_deleteTokens();
$this->_deleteNonces();
parent::delete();
}
function _deleteTokens()
{
$token = new Token();
$token->consumer_key = $this->consumer_key;
$token->delete();
}
function _deleteNonces()
{
$nonce = new Nonce();
$nonce->consumer_key = $this->consumer_key;
$nonce->delete();
}
} }

View File

@ -137,4 +137,21 @@ class Oauth_application extends Memcached_DataObject
} }
} }
function delete()
{
$this->_deleteAppUsers();
$consumer = $this->getConsumer();
$consumer->delete();
parent::delete();
}
function _deleteAppUsers()
{
$oauser = new Oauth_application_user();
$oauser->application_id = $this->id;
$oauser->delete();
}
} }

View File

@ -353,7 +353,7 @@ notice_id = K
id = 129 id = 129
owner = 129 owner = 129
consumer_key = 130 consumer_key = 130
name = 130 name = 2
description = 2 description = 2
icon = 130 icon = 130
source_url = 2 source_url = 2
@ -367,6 +367,7 @@ modified = 384
[oauth_application__keys] [oauth_application__keys]
id = N id = N
name = U
[oauth_application_user] [oauth_application_user]
profile_id = 129 profile_id = 129

View File

@ -214,7 +214,7 @@ create table oauth_application (
id integer auto_increment primary key comment 'unique identifier', id integer auto_increment primary key comment 'unique identifier',
owner integer not null comment 'owner of the application' references profile (id), 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), consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key),
name varchar(255) not null comment 'name of the application', name varchar(255) unique key comment 'name of the application',
description varchar(255) comment 'description of the application', description varchar(255) comment 'description of the application',
icon varchar(255) not null comment 'application icon', icon varchar(255) not null comment 'application icon',
source_url varchar(255) comment 'application homepage - used for source link', source_url varchar(255) comment 'application homepage - used for source link',
@ -230,7 +230,7 @@ create table oauth_application (
create table oauth_application_user ( create table oauth_application_user (
profile_id integer not null comment 'user of the application' references profile (id), 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), 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', access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write',
token varchar(255) comment 'request or access token', token varchar(255) comment 'request or access token',
created datetime not null comment 'date this record was created', created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified', modified timestamp comment 'date this record was modified',

View File

@ -1249,10 +1249,27 @@ class ApiAction extends Action
case 'api': case 'api':
break; break;
default: default:
$name = null;
$url = null;
$ns = Notice_source::staticGet($source); $ns = Notice_source::staticGet($source);
if ($ns) { if ($ns) {
$source_name = '<a href="' . $ns->url . '">' . $ns->name . '</a>'; $name = $ns->name;
$url = $ns->url;
} else {
$app = Oauth_application::staticGet('name', $source);
if ($app) {
$name = $app->name;
$url = $app->source_url;
} }
}
if (!empty($name) && !empty($url)) {
$source_name = '<a href="' . $url . '">' . $name . '</a>';
}
break; break;
} }
return $source_name; return $source_name;

View File

@ -55,6 +55,7 @@ class ApiAuthAction extends ApiAction
{ {
var $auth_user_nickname = null; var $auth_user_nickname = null;
var $auth_user_password = null; var $auth_user_password = null;
var $oauth_source = null;
/** /**
* Take arguments for running, looks for an OAuth request, * Take arguments for running, looks for an OAuth request,
@ -73,21 +74,19 @@ class ApiAuthAction extends ApiAction
// NOTE: $this->auth_user has to get set in prepare(), not handle(), // NOTE: $this->auth_user has to get set in prepare(), not handle(),
// because subclasses do stuff with it in their prepares. // because subclasses do stuff with it in their prepares.
if ($this->requiresAuth()) {
$oauthReq = $this->getOAuthRequest(); $oauthReq = $this->getOAuthRequest();
if (!$oauthReq) { if (!$oauthReq) {
if ($this->requiresAuth()) {
$this->checkBasicAuthUser(true); $this->checkBasicAuthUser(true);
} else { } else {
$this->checkOAuthRequest($oauthReq);
}
} else {
// Check to see if a basic auth user is there even // Check to see if a basic auth user is there even
// if one's not required // if one's not required
$this->checkBasicAuthUser(false); $this->checkBasicAuthUser(false);
} }
} else {
$this->checkOAuthRequest($oauthReq);
}
// Reject API calls with the wrong access level // Reject API calls with the wrong access level
@ -108,7 +107,6 @@ class ApiAuthAction extends ApiAction
* This is to avoid doign any unnecessary DB lookups. * This is to avoid doign any unnecessary DB lookups.
* *
* @return mixed the OAuthRequest or false * @return mixed the OAuthRequest or false
*
*/ */
function getOAuthRequest() function getOAuthRequest()
@ -137,7 +135,6 @@ class ApiAuthAction extends ApiAction
* @param OAuthRequest $request the OAuth Request * @param OAuthRequest $request the OAuth Request
* *
* @return nothing * @return nothing
*
*/ */
function checkOAuthRequest($request) function checkOAuthRequest($request)

View File

@ -159,5 +159,32 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
} }
} }
/**
* Revoke specified access token
*
* Revokes the token specified by $token_key.
* Throws exceptions in case of error.
*
* @param string $token_key the token to be revoked
* @param int $type type of token (0 = req, 1 = access)
*
* @access public
*
* @return void
*/
public function revoke_token($token_key, $type = 0) {
$rt = new Token();
$rt->tok = $token_key;
$rt->type = $type;
$rt->state = 0;
if (!$rt->find(true)) {
throw new Exception('Tried to revoke unknown token');
}
if (!$rt->delete()) {
throw new Exception('Failed to delete revoked token');
}
}
} }

View File

@ -486,12 +486,28 @@ class NoticeListItem extends Widget
$this->out->element('span', 'device', $source_name); $this->out->element('span', 'device', $source_name);
break; break;
default: default:
$name = null;
$url = null;
$ns = Notice_source::staticGet($this->notice->source); $ns = Notice_source::staticGet($this->notice->source);
if ($ns) { if ($ns) {
$name = $ns->name;
$url = $ns->url;
} else {
$app = Oauth_application::staticGet('name', $this->notice->source);
if ($app) {
$name = $app->name;
$url = $app->source_url;
}
}
if (!empty($name) && !empty($url)) {
$this->out->elementStart('span', 'device'); $this->out->elementStart('span', 'device');
$this->out->element('a', array('href' => $ns->url, $this->out->element('a', array('href' => $url,
'rel' => 'external'), 'rel' => 'external'),
$ns->name); $name);
$this->out->elementEnd('span'); $this->out->elementEnd('span');
} else { } else {
$this->out->element('span', 'device', $source_name); $this->out->element('span', 'device', $source_name);

View File

@ -152,6 +152,10 @@ class Router
array('action' => 'editapplication'), array('action' => 'editapplication'),
array('id' => '[0-9]+') array('id' => '[0-9]+')
); );
$m->connect('settings/oauthapps/delete/:id',
array('action' => 'deleteapplication'),
array('id' => '[0-9]+')
);
// search // search

View File

@ -182,21 +182,6 @@ class UserFlagPlugin extends Plugin
return true; return true;
} }
/**
* Add our plugin's CSS to page output
*
* @param Action $action action being shown
*
* @return boolean hook result
*/
function onEndShowStatusNetStyles($action)
{
$action->cssLink(common_path('plugins/UserFlag/userflag.css'),
null, 'screen, projection, tv');
return true;
}
/** /**
* Initialize any flagging buttons on the page * Initialize any flagging buttons on the page
* *

View File

@ -54,7 +54,7 @@ class ClearFlagForm extends ProfileActionForm
function formClass() function formClass()
{ {
return 'form_entity_clearflag'; return 'form_user_clearflag';
} }
/** /**

View File

@ -1,4 +0,0 @@
.entity_flag input.submit,
.entity_flag p {
background:url(icon_flag.gif) 5px 5px no-repeat;
}

16
scripts/setconfig.php Normal file → Executable file
View File

@ -28,6 +28,7 @@ setconfig.php [options] [section] [setting] <value>
With three args, set the setting to the value. With three args, set the setting to the value.
With two args, just show the setting. With two args, just show the setting.
With -d, delete the setting. With -d, delete the setting.
With no args, lists all currently set values.
[section] section to use (required) [section] section to use (required)
[setting] setting to use (required) [setting] setting to use (required)
@ -39,6 +40,21 @@ END_OF_SETCONFIG_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc'; require_once INSTALLDIR.'/scripts/commandline.inc';
if (empty($args)) {
$count = 0;
$config = new Config();
$config->find();
while ($config->fetch()) {
$count++;
printf("%-20s %-20s %s\n", $config->section, $config->setting,
var_export($config->value, true));
}
if ($count == 0) {
print "No configuration set in database for this site.\n";
}
exit(0);
}
if (count($args) < 2 || count($args) > 3) { if (count($args) < 2 || count($args) > 3) {
show_help(); show_help();
exit(1); exit(1);

View File

@ -632,7 +632,8 @@ margin-bottom:18px;
.entity_profile .entity_url, .entity_profile .entity_url,
.entity_profile .entity_note, .entity_profile .entity_note,
.entity_profile .entity_tags, .entity_profile .entity_tags,
.entity_profile .entity_aliases { .entity_profile .entity_aliases,
.entity_profile .entity_statistics {
margin-left:113px; margin-left:113px;
margin-bottom:4px; margin-bottom:4px;
} }
@ -1023,6 +1024,7 @@ float:none;
} }
#content .notice .entry-title { #content .notice .entry-title {
margin-left:59px; margin-left:59px;
margin-right:7px;
} }
.vcard .url { .vcard .url {
@ -1411,6 +1413,9 @@ margin-bottom:18px;
.hentry .entry-content li li { .hentry .entry-content li li {
margin-left:18px; margin-left:18px;
} }
.hentry .entry-content .form_settings ul {
margin-left:0;
}
#content #plugin_authors { #content #plugin_authors {
min-width:122px; min-width:122px;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 B

View File

Before

Width:  |  Height:  |  Size: 80 B

After

Width:  |  Height:  |  Size: 80 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

@ -18,7 +18,7 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
font-size:1em; font-size:1em;
} }
address { address {
margin-right:5.7%; margin-right:5.3%;
} }
input, textarea, select { input, textarea, select {
border-width:2px; border-width:2px;
@ -189,7 +189,10 @@ button.close,
.notice-options .repeated, .notice-options .repeated,
.form_notice label[for=notice_data-geo], .form_notice label[for=notice_data-geo],
button.minimize, button.minimize,
.form_reset_key input.submit { .form_reset_key input.submit,
.entity_clear input.submit,
.entity_flag input.submit,
.entity_flag p {
background-image:url(../../base/images/icons/icons-01.gif); background-image:url(../../base/images/icons/icons-01.gif);
background-repeat:no-repeat; background-repeat:no-repeat;
background-color:transparent; background-color:transparent;
@ -338,6 +341,13 @@ background-position: 5px -1511px;
.form_reset_key input.submit { .form_reset_key input.submit {
background-position: 5px -1973px; background-position: 5px -1973px;
} }
.entity_clear input.submit {
background-position: 5px -2039px;
}
.entity_flag input.submit,
.entity_flag p {
background-position: 5px -2105px;
}
/* NOTICES */ /* NOTICES */
.notice .attachment { .notice .attachment {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -189,7 +189,10 @@ button.close,
.notice-options .repeated, .notice-options .repeated,
.form_notice label[for=notice_data-geo], .form_notice label[for=notice_data-geo],
button.minimize, button.minimize,
.form_reset_key input.submit { .form_reset_key input.submit,
.entity_clear input.submit,
.entity_flag input.submit,
.entity_flag p {
background-image:url(../../base/images/icons/icons-01.gif); background-image:url(../../base/images/icons/icons-01.gif);
background-repeat:no-repeat; background-repeat:no-repeat;
background-color:transparent; background-color:transparent;
@ -337,6 +340,13 @@ background-position: 5px -1511px;
.form_reset_key input.submit { .form_reset_key input.submit {
background-position: 5px -1973px; background-position: 5px -1973px;
} }
.entity_clear input.submit {
background-position: 5px -2039px;
}
.entity_flag input.submit,
.entity_flag p {
background-position: 5px -2105px;
}
/* NOTICES */ /* NOTICES */
.notice .attachment { .notice .attachment {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB