CSteipp has submitted this change and it was merged.
Change subject: Added Special:MWOAuthManageMyGrants page
......................................................................
Added Special:MWOAuthManageMyGrants page
* Various small cleanups
Change-Id: I669bd4b750cdfafd18dad60d8cdabdc1675113f4
---
M OAuth.config.php
M OAuth.setup.php
M backend/MWOAuthConsumer.php
A backend/MWOAuthConsumerAcceptance.php
M backend/MWOAuthDAO.php
A control/MWOAuthConsumerAcceptanceSubmitControl.php
M control/MWOAuthConsumerSubmitControl.php
M control/MWOAuthDAOAccessControl.php
M control/MWOAuthSubmitControl.php
M frontend/MWOAuthUI.setup.php
M frontend/language/MWOAuth.i18n.php
M frontend/specialpages/actions/MWOAuthManageConsumers.php
A frontend/specialpages/actions/MWOAuthManageMyGrants.php
13 files changed, 720 insertions(+), 84 deletions(-)
Approvals:
CSteipp: Verified; Looks good to me, approved
diff --git a/OAuth.config.php b/OAuth.config.php
index 36a9ff6..fc4e9d0 100644
--- a/OAuth.config.php
+++ b/OAuth.config.php
@@ -12,6 +12,7 @@
$wgAvailableRights[] = 'mwoauthsuppress';
$wgAvailableRights[] = 'mwoauthviewsuppressed';
$wgAvailableRights[] = 'mwoauthviewprivate';
+$wgAvailableRights[] = 'mwoauthmanagemyconsumers';
# End of configuration variables.
# ########
diff --git a/OAuth.setup.php b/OAuth.setup.php
index 6714af5..8b30872 100644
--- a/OAuth.setup.php
+++ b/OAuth.setup.php
@@ -35,6 +35,7 @@
$classes['MWOAuthConsumerRegistration'] =
"$spActionDir/MWOAuthConsumerRegistration.php";
$classes['MWOAuthManageConsumers'] =
"$spActionDir/MWOAuthManageConsumers.php";
+ $classes['MWOAuthManageMyGrants'] =
"$spActionDir/MWOAuthManageMyGrants.php";
# Special:MWOAuth/authorize
# Special:MWOAuth/initiate?
# Special:MWOAuth/token?
@@ -45,11 +46,14 @@
# Data access objects
$classes['MWOAuthDAO'] = "$backendDir/MWOAuthDAO.php";
$classes['MWOAuthConsumer'] = "$backendDir/MWOAuthConsumer.php";
+ $classes['MWOAuthConsumerAcceptance'] =
"$backendDir/MWOAuthConsumerAcceptance.php";
# Control logic
$classes['MWOAuthDAOAccessControl'] =
"$controlDir/MWOAuthDAOAccessControl.php";
$classes['MWOAuthSubmitControl'] =
"$controlDir/MWOAuthSubmitControl.php";
$classes['MWOAuthConsumerSubmitControl'] =
"$controlDir/MWOAuthConsumerSubmitControl.php";
+ $classes['MWOAuthConsumerAcceptanceSubmitControl'] =
+
"$controlDir/MWOAuthConsumerAcceptanceSubmitControl.php";
# Schema changes
$classes['MWOAuthUpdaterHooks'] =
"$schemaDir/MWOAuthUpdater.hooks.php";
diff --git a/backend/MWOAuthConsumer.php b/backend/MWOAuthConsumer.php
index d18e6f4..c6066e9 100644
--- a/backend/MWOAuthConsumer.php
+++ b/backend/MWOAuthConsumer.php
@@ -26,7 +26,7 @@
protected $id;
/** @var string Hex token */
protected $consumerKey;
- /** @var integer Publisher user ID */
+ /** @var integer Publisher user ID (on central wiki) */
protected $userId;
/** @var string Version used for handshake breaking changes */
protected $version;
@@ -46,6 +46,8 @@
protected $secretKey;
/** @var string RSA key */
protected $rsaKey;
+ /** @var array List of grants */
+ protected $grants;
/** @var array IP restrictions */
protected $restrictions;
/** @var integer MWOAuthConsumer::STAGE_* constant */
@@ -182,7 +184,8 @@
$row['oarc_stage_timestamp'] = $db->timestamp(
$row['oarc_stage_timestamp'] );
$row['oarc_restrictions'] = FormatJSON::encode(
$row['oarc_restrictions'] );
$row['oarc_grants'] = FormatJSON::encode( $row['oarc_grants'] );
- $row['oarc_email_authenticated'] = $db->timestamp(
$row['oarc_email_authenticated'] );
+ $row['oarc_email_authenticated'] =
+ $db->timestampOrNull( $row['oarc_email_authenticated']
);
return $row;
}
@@ -191,7 +194,8 @@
$row['oarc_stage_timestamp'] = wfTimestamp( TS_MW,
$row['oarc_stage_timestamp'] );
$row['oarc_restrictions'] = FormatJSON::decode(
$row['oarc_restrictions'], true );
$row['oarc_grants'] = FormatJSON::decode( $row['oarc_grants'],
true );
- $row['oarc_email_authenticated'] = wfTimestamp( TS_MW,
$row['oarc_email_authenticated'] );
+ $row['oarc_email_authenticated'] =
+ wfTimestampOrNull( TS_MW,
$row['oarc_email_authenticated'] );
return $row;
}
diff --git a/backend/MWOAuthConsumerAcceptance.php
b/backend/MWOAuthConsumerAcceptance.php
new file mode 100644
index 0000000..33a4687
--- /dev/null
+++ b/backend/MWOAuthConsumerAcceptance.php
@@ -0,0 +1,110 @@
+<?php
+/*
+ (c) Aaron Schulz 2013, GPL
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ http://www.gnu.org/copyleft/gpl.html
+*/
+
+/**
+ * Representation of an OAuth consumer acceptance
+ */
+class MWOAuthConsumerAcceptance extends MWOAuthDAO {
+ /** @var string Wiki ID the application can be used on (or "*" for all)
*/
+ protected $wiki;
+ /** @var integer Publisher user ID (on central wiki) */
+ protected $userId;
+ /** @var integer */
+ protected $consumerId;
+ /** @var string Hex token */
+ protected $accessToken;
+ /** @var string Hex token */
+ protected $secretToken;
+ /** @var array List of grants */
+ protected $grants;
+ /** @var string TS_MW timestamp of acceptance */
+ protected $accepted;
+
+ protected static function getSchema() {
+ return array(
+ 'idField' => 'accessToken',
+ 'table' => 'oauth_accepted_consumer',
+ 'fieldColumnMap' => array(
+ 'wiki' => 'oaac_wiki',
+ 'userId' => 'oaac_user_id',
+ 'consumerId' => 'oaac_consumer_id',
+ 'accessToken' => 'oaac_access_token',
+ 'accessSecret' => 'oaac_access_secret',
+ 'grants' => 'oaac_grants',
+ 'accepted' => 'oaac_accepted'
+ ),
+ );
+ }
+
+ protected static function getFieldPermissionChecks() {
+ return array(
+ 'accessSecret' => 'userCanSeePrivate'
+ );
+ }
+
+ /**
+ * @param DatabaseBase $db
+ * @param string $token Access token
+ * @param integer $flags MWOAuthConsumerAcceptance::READ_* bitfield
+ * @return MWOAuthConsumerAcceptance|bool
+ */
+ public static function newFromToken( DatabaseBase $db, $token, $flags =
0 ) {
+ $row = $db->selectRow( static::getTable(),
+ array_values( static::getFieldColumnMap() ),
+ array( 'oaac_access_token' => $token ),
+ __METHOD__,
+ ( $flags & self::READ_LOCKING ) ? array( 'FOR UPDATE' )
: array()
+ );
+
+ if ( $row ) {
+ $consumer = new self();
+ $consumer->loadFromRow( $db, $row );
+ return $consumer;
+ } else {
+ return false;
+ }
+ }
+
+ protected function normalizeValues() {
+ $this->userId = (int)$this->userId;
+ $this->consumerId = (int)$this->consumerId;
+ $this->accepted = wfTimestamp( TS_MW, $this->accepted );
+ }
+
+ protected function encodeRow( DatabaseBase $db, $row ) {
+ $row['oaac_grants'] = FormatJSON::encode( $row['oaac_grants'] );
+ $row['oaac_accepted'] = $db->timestamp( $row['oaac_accepted'] );
+ return $row;
+ }
+
+ protected function decodeRow( DatabaseBase $db, $row ) {;
+ $row['oaac_grants'] = FormatJSON::decode( $row['oaac_grants'],
true );
+ $row['oaac_accepted'] = wfTimestamp( TS_MW,
$row['oaac_accepted'] );
+ return $row;
+ }
+
+ protected function userCanSeePrivate( $name, RequestContext $context ) {
+ if ( !$context->getUser()->isAllowed( 'mwoauthviewprivate' ) ) {
+ return $context->msg( 'mwoauth-field-private' );
+ } else {
+ return true;
+ }
+ }
+}
diff --git a/backend/MWOAuthDAO.php b/backend/MWOAuthDAO.php
index a9113e1..dfb0aeb 100644
--- a/backend/MWOAuthDAO.php
+++ b/backend/MWOAuthDAO.php
@@ -22,6 +22,8 @@
* Representation of a Data Access Object
*/
abstract class MWOAuthDAO implements IDBAccessObject {
+ private $daoOrigin = 'new'; // string; object construction origin
+
/**
* @throws Exception
*/
@@ -138,7 +140,7 @@
public function save( DatabaseBase $dbw ) {
$uniqueId = $this->getIdValue();
$idColumn = static::getIdColumn();
- if ( $uniqueId ) {
+ if ( $this->daoOrigin === 'db' ) {
$dbw->update(
static::getTable(),
$this->getRowArray( $dbw ),
@@ -314,6 +316,7 @@
$values[$field] = $row[$column];
}
$this->loadFromValues( $values );
+ $this->daoOrigin = 'db';
}
/**
diff --git a/control/MWOAuthConsumerAcceptanceSubmitControl.php
b/control/MWOAuthConsumerAcceptanceSubmitControl.php
new file mode 100644
index 0000000..422ca9d
--- /dev/null
+++ b/control/MWOAuthConsumerAcceptanceSubmitControl.php
@@ -0,0 +1,142 @@
+<?php
+/*
+ (c) Aaron Schulz 2013, GPL
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ http://www.gnu.org/copyleft/gpl.html
+*/
+
+/**
+ * This handles the core logic of submitting/approving application
+ * consumer requests and the logic of managing approved consumers
+ *
+ * @TODO: improve error messages
+ */
+class MWOAuthConsumerAcceptanceSubmitControl extends MWOAuthSubmitControl {
+ protected function getRequiredFields() {
+ return array(
+ 'accept' => array(
+ 'consumerKey' => '/^[0-9a-f]{32}$/',
+ 'wiki' => function( $s ) {
+ return WikiMap::getWiki( $s ) || $s ===
'*'; },
+ 'grants' => function( $s ) {
+ // @TODO: beef up
+ return is_array( FormatJSON::decode(
$s, true ) ); }
+ ),
+ 'update' => array(
+ 'accessToken' => '/^[0-9a-f]{32}$/',
+ 'wiki' => function( $s ) {
+ return WikiMap::getWiki( $s ) || $s ===
'*'; },
+ 'grants' => function( $s ) {
+ // @TODO: beef up
+ return is_array( FormatJSON::decode(
$s, true ) ); }
+ ),
+ 'renounce' => array(
+ 'accessToken' => '/^[0-9a-f]{32}$/',
+ ),
+ );
+ }
+
+ protected function checkBasePermissions() {
+ $user = $this->getUser();
+ if ( !$user->getID() ) {
+ return $this->failure( 'not_logged_in',
'badaccess-group0' );
+ } elseif ( !$user->isAllowed( 'mwoauthmanagemygrants' ) ) {
+ return $this->failure( 'permission_denied',
'badaccess-group0' );
+ } elseif ( wfReadOnly() ) {
+ return $this->failure( 'readonly', 'readonlytext',
wfReadOnlyReason() );
+ } elseif ( !MWOAuthUtils::isCentralWiki() ) { // sanity
+ // We attach consumers to the ID of a user on the
management wiki
+ throw new MWException( "This can only be used from the
OAuth management wiki." );
+ }
+ return $this->success();
+ }
+
+ protected function processAction( $action ) {
+ global $wgMemc;
+
+ $user = $this->getUser(); // proposer or admin
+ $dbw = MWOAuthUtils::getCentralDB( DB_MASTER );
+
+ switch ( $action ) {
+ /*
+ case 'accept': // @TODO: unused (WIP)
+ $cmr = MWOAuthConsumer::newFromKey( $dbw,
$this->vals['consumerKey'] );
+ if ( !$cmr ) {
+ return $this->failure( 'invalid_consumer_key',
'mwoauth-invalid-consumer-key' );
+ } elseif ( $cmr->get( 'stage' ) !==
MWOAuthConsumer::STAGE_APPROVED ) {
+ return $this->failure( 'permission_denied',
'badaccess-group0' );
+ }
+
+ // @TODO: handle exceptions
+ $store = new MWOAuthDataStore( $wgMemc,
MWOAuthUtils::getCentralDB( DB_MASTER ) );
+ $oauthServer = new MWOAuthServer( $store );
+ $oauthServer->add_signature_method( new
OAuthSignatureMethod_HMAC_SHA1() );
+ $oauthServer->add_signature_method( new
MWOAuthSignatureMethod_RSA_SHA1( $store ) );
+
+ $callback = $oauthServer->authorize(
+ $this->vals['consumerKey'],
$this->vals['requestToken'], $this->getUser() );
+
+ // WIP: PUT THIS IN authorize()
+ $cmra = MWOAuthConsumerAcceptance::newFromArray( array(
+ 'wiki' => $this->vals['wiki'],
+ 'userId' => $this->getUser()->getId(),
+ 'consumerId' => $cmr->getId(),
+ 'accessToken' => ...,
+ 'accessSecret' => ...,
+ 'grants' => FormatJSON::decode(
$this->vals['grants'], true ),
+ 'accepted' => wfTimestampNow()
+ ) );
+ return $this->success( $cmra );
+ $cmra->save();
+ */
+ case 'update':
+ $cmra = MWOAuthConsumerAcceptance::newFromToken( $dbw,
$this->vals['accessToken'] );
+ if ( !$cmra ) {
+ return $this->failure( 'invalid_access_token',
'mwoauth-invalid-access-token' );
+ } elseif ( $cmra->get( 'userId' ) !==
$this->getUser()->getId() ) {
+ return $this->failure( 'invalid_access_token',
'mwoauth-invalid-access-token' );
+ }
+
+ $cmra->setFields( array(
+ 'wiki' => $this->vals['wiki'],
+ 'grants' => FormatJSON::decode(
$this->vals['grants'], true ) ) );
+ $cmra->save( $dbw );
+
+ return $this->success( $cmra );
+ case 'renounce':
+ $cmra = MWOAuthConsumerAcceptance::newFromToken( $dbw,
$this->vals['accessToken'] );
+ if ( !$cmra ) {
+ return $this->failure( 'invalid_access_token',
'mwoauth-invalid-access-token' );
+ } elseif ( $cmra->get( 'userId' ) !==
$this->getUser()->getId() ) {
+ return $this->failure( 'invalid_access_token',
'mwoauth-invalid-access-token' );
+ }
+
+ $cmra->delete( $dbw );
+
+ return $this->success( $cmra );
+ }
+ }
+
+ /**
+ * @param DatabaseBase $db
+ * @param int $userId
+ * @return Title
+ */
+ protected function getLogTitle( DatabaseBase $db, $userId ) {
+ $name = $db->selectField( 'user', 'user_name', array( 'user_id'
=> $userId ) );
+ return Title::makeTitleSafe( NS_USER, $name );
+ }
+}
diff --git a/control/MWOAuthConsumerSubmitControl.php
b/control/MWOAuthConsumerSubmitControl.php
index b721203..8eae118 100644
--- a/control/MWOAuthConsumerSubmitControl.php
+++ b/control/MWOAuthConsumerSubmitControl.php
@@ -19,14 +19,13 @@
*/
/**
- * Handle the logic of submitting a application consumer request
+ * This handles the core logic of approving/disabling consumers
+ * from using particular user accounts
*
* @TODO: improve error messages
*/
class MWOAuthConsumerSubmitControl extends MWOAuthSubmitControl {
- protected function getRequiredFields() {
- return array(
- // @TODO: handle input trimming
+ protected function getRequiredFields() {return array(
// Proposer (application administrator) actions:
'propose' => array(
'name' => '/^.{1,128}$/',
@@ -137,16 +136,9 @@
$logEntry->setTarget( $this->getLogTitle( $dbw,
$cmr->get( 'userId' ) ) );
$logEntry->setComment( $this->vals['description'] );
$logEntry->setParameters( array( '4:consumer' =>
$cmr->get( 'consumerKey' ) ) );
- $logid = $logEntry->insert( $dbw );
- // @TODO: Core wrapper
- $dbw->insert( 'log_search',
- array(
- 'ls_field' => 'OAuthConsumer',
- 'ls_value' => $cmr->get( 'consumerKey'
),
- 'ls_log_id' => $logid ),
- __METHOD__,
- 'IGNORE'
- );
+ $logEntry->setRelations( array(
+ 'OAuthConsumer' => array( $cmr->get(
'consumerKey' ) )
+ ) );
return $this->success( $cmr );
case 'update':
@@ -178,16 +170,10 @@
$logEntry->setTarget( $this->getLogTitle( $dbw,
$cmr->get( 'userId' ) ) );
$logEntry->setComment( $this->vals['reason'] );
$logEntry->setParameters( array( '4:consumer' =>
$cmr->get( 'consumerKey' ) ) );
+ $logEntry->setRelations( array(
+ 'OAuthConsumer' => array( $cmr->get(
'consumerKey' ) )
+ ) );
$logid = $logEntry->insert( $dbw );
- // @TODO: Core wrapper
- $dbw->insert( 'log_search',
- array(
- 'ls_field' => 'OAuthConsumer',
- 'ls_value' => $cmr->get( 'consumerKey'
),
- 'ls_log_id' => $logid ),
- __METHOD__,
- 'IGNORE'
- );
return $this->success( $cmr );
case 'approve':
@@ -219,16 +205,10 @@
$logEntry->setTarget( $this->getLogTitle( $dbw,
$cmr->get( 'userId' ) ) );
$logEntry->setComment( $this->vals['reason'] );
$logEntry->setParameters( array( '4:consumer' =>
$cmr->get( 'consumerKey' ) ) );
+ $logEntry->setRelations( array(
+ 'OAuthConsumer' => array( $cmr->get(
'consumerKey' ) )
+ ) );
$logid = $logEntry->insert( $dbw );
- // @TODO: Core wrapper
- $dbw->insert( 'log_search',
- array(
- 'ls_field' => 'OAuthConsumer',
- 'ls_value' => $cmr->get( 'consumerKey'
),
- 'ls_log_id' => $logid ),
- __METHOD__,
- 'IGNORE'
- );
// @TODO: email/notifications?
@@ -258,16 +238,10 @@
$logEntry->setTarget( $this->getLogTitle( $dbw,
$cmr->get( 'userId' ) ) );
$logEntry->setComment( $this->vals['reason'] );
$logEntry->setParameters( array( '4:consumer' =>
$cmr->get( 'consumerKey' ) ) );
+ $logEntry->setRelations( array(
+ 'OAuthConsumer' => array( $cmr->get(
'consumerKey' ) )
+ ) );
$logid = $logEntry->insert( $dbw );
- // @TODO: Core wrapper
- $dbw->insert( 'log_search',
- array(
- 'ls_field' => 'OAuthConsumer',
- 'ls_value' => $cmr->get( 'consumerKey'
),
- 'ls_log_id' => $logid ),
- __METHOD__,
- 'IGNORE'
- );
// @TODO: email/notifications?
@@ -301,16 +275,10 @@
$logEntry->setTarget( $this->getLogTitle( $dbw,
$cmr->get( 'userId' ) ) );
$logEntry->setComment( $this->vals['reason'] );
$logEntry->setParameters( array( '4:consumer' =>
$cmr->get( 'consumerKey' ) ) );
+ $logEntry->setRelations( array(
+ 'OAuthConsumer' => array( $cmr->get(
'consumerKey' ) )
+ ) );
$logid = $logEntry->insert( $dbw );
- // @TODO: Core wrapper
- $dbw->insert( 'log_search',
- array(
- 'ls_field' => 'OAuthConsumer',
- 'ls_value' => $cmr->get( 'consumerKey'
),
- 'ls_log_id' => $logid ),
- __METHOD__,
- 'IGNORE'
- );
// @TODO: email/notifications?
@@ -340,16 +308,10 @@
$logEntry->setTarget( $this->getLogTitle( $dbw,
$cmr->get( 'userId' ) ) );
$logEntry->setComment( $this->vals['reason'] );
$logEntry->setParameters( array( '4:consumer' =>
$cmr->get( 'consumerKey' ) ) );
+ $logEntry->setRelations( array(
+ 'OAuthConsumer' => array( $cmr->get(
'consumerKey' ) )
+ ) );
$logid = $logEntry->insert( $dbw );
- // @TODO: Core wrapper
- $dbw->insert( 'log_search',
- array(
- 'ls_field' => 'OAuthConsumer',
- 'ls_value' => $cmr->get( 'consumerKey'
),
- 'ls_log_id' => $logid ),
- __METHOD__,
- 'IGNORE'
- );
// @TODO: email/notifications?
diff --git a/control/MWOAuthDAOAccessControl.php
b/control/MWOAuthDAOAccessControl.php
index bb6054a..d303534 100644
--- a/control/MWOAuthDAOAccessControl.php
+++ b/control/MWOAuthDAOAccessControl.php
@@ -69,8 +69,8 @@
*/
final public function get( $name, $sCallback = null ) {
$msg = $this->dao->userCanAccess( $name, $this->context );
- if ( $msg instanceof Message ) {
- return $msg;
+ if ( $msg !== true ) {
+ return $msg; // should be a Message object
} else {
$value = $this->dao->get( $name );
return $sCallback ? call_user_func( $sCallback, $value
) : $value;
diff --git a/control/MWOAuthSubmitControl.php b/control/MWOAuthSubmitControl.php
index c8fa742..9829898 100644
--- a/control/MWOAuthSubmitControl.php
+++ b/control/MWOAuthSubmitControl.php
@@ -94,12 +94,18 @@
*/
protected function validateFields( array $required ) {
foreach ( $required as $field => $validator ) {
- if ( is_null( $this->vals[$field] ) ) {
+ if ( !isset( $this->vals[$field] ) ) {
// @TODO: check for field-specific message first
return $this->failure( "missing_field_$field",
'mwoauth-missing-field', $field );
+ } elseif ( !is_scalar( $this->vals[$field] ) ) {
+ // @TODO: check for field-specific message first
+ return $this->failure( "invalid_field_$field",
'mwoauth-invalid-field', $field );
+ }
+ if ( is_string( $this->vals[$field] ) ) {
+ $this->vals[$field] = trim( $this->vals[$field]
); // trim all input
}
$valid = is_string( $validator ) // regex
- ? is_scalar( $this->vals[$field] ) &&
preg_match( $validator, $this->vals[$field] )
+ ? preg_match( $validator, $this->vals[$field] )
: $validator( $this->vals[$field] );
if ( !$valid ) {
// @TODO: check for field-specific message first
diff --git a/frontend/MWOAuthUI.setup.php b/frontend/MWOAuthUI.setup.php
index 1f83b48..f2343f7 100644
--- a/frontend/MWOAuthUI.setup.php
+++ b/frontend/MWOAuthUI.setup.php
@@ -15,6 +15,7 @@
$groups['MWOAuthConsumerRegistration'] = 'users';
$pages['MWOAuthManageConsumers'] =
'MWOAuthManageConsumers';
$groups['MWOAuthManageConsumers'] = 'users';
+ $pages['MWOAuthManageMyGrants'] =
'MWOAuthManageMyGrants';
}
}
diff --git a/frontend/language/MWOAuth.i18n.php
b/frontend/language/MWOAuth.i18n.php
index 58517a2..68c47fa 100644
--- a/frontend/language/MWOAuth.i18n.php
+++ b/frontend/language/MWOAuth.i18n.php
@@ -20,15 +20,17 @@
'mwoauth-consumer-key' => 'Consumer key:',
'mwoauth-consumer-name' => 'Application name:',
'mwoauth-consumer-version' => 'Major version:',
+ 'mwoauth-consumer-user' => 'Publisher:',
'mwoauth-consumer-stage' => 'Current status:',
'mwoauth-consumer-email' => 'Contact E-mail address:',
'mwoauth-consumer-description' => 'Application description:',
'mwoauth-consumer-callbackurl' => 'OAuth "callback" URL:',
- 'mwoauth-consumer-grantsneeded' => 'Grants used (JSON):',
- 'mwoauth-consumer-wiki' => 'Single-wiki usage:',
+ 'mwoauth-consumer-grantsneeded' => 'Applicable grants (JSON):',
+ 'mwoauth-consumer-wiki' => 'Applicable wiki:',
'mwoauth-consumer-restrictions' => 'Usage restictions (JSON):',
'mwoauth-consumer-rsakey' => 'Consumer RSA key:',
'mwoauth-consumer-secretkey' => 'Consumer secret token:',
+ 'mwoauth-consumer-accesstoken' => 'Access token:',
'mwoauth-consumer-reason' => 'Reason:',
'mwoauth-consumer-alreadyexists' => 'A consumer with this
name/version/author combination already exists',
'mwoauth-consumer-not-accepted' => 'Cannot update information for a
pending consumer request',
@@ -37,6 +39,7 @@
'mwoauth-consumer-not-disabled' => 'The consumer is not currently
disabled',
'mwoauth-consumer-not-approved' => 'The consumer is not approved (it
may have been disabled)',
'mwoauth-invalid-consumer-key' => 'No consumer exists with the given
key.',
+ 'mwoauth-invalid-access-token' => 'No access token exists with the
given key.',
'mwoauth-consumer-stage-proposed' => 'proposed',
'mwoauth-consumer-stage-rejected' => 'rejected',
@@ -112,6 +115,32 @@
'mwoauthmanageconsumers-success-disabled' => 'Consumer successfuly
disabled.',
'mwoauthmanageconsumers-success-reanable' => 'Consumer successfuly
re-enabled.',
+ 'mwoauthmanagemygrants' => 'Manage account OAuth grants',
+ 'mwoauthmanagemygrants-navigation' => 'Navigation:',
+ 'mwoauthmanagemygrants-showlist' => 'Consumer list',
+ 'mwoauthmanagemygrants-none' => 'No consumers have access on behalf of
your account.',
+ 'mwoauthmanagemygrants-name' => 'Consumer name',
+ 'mwoauthmanagemygrants-user' => 'Publisher',
+ 'mwoauthmanagemygrants-description' => 'Description',
+ 'mwoauthmanagemygrants-wiki' => 'Applicable wiki',
+ 'mwoauthmanagemygrants-wikiallowed' => 'Allowed on wiki',
+ 'mwoauthmanagemygrants-grants' => 'Applicable grants',
+ 'mwoauthmanagemygrants-grantsallowed' => 'Grants allowed:',
+ 'mwoauthmanagemygrants-applicablegrantsallowed' => 'Applicable grants
allowed:',
+ 'mwoauthmanagemygrants-consumerkey' => 'Consumer key',
+ 'mwoauthmanagemygrants-review' => 'Review/manage access',
+ 'mwoauthmanagemygrants-grantaccept' => 'Granted to consumer',
+ 'mwoauthmanagemygrants-confirm-text' => 'Use the form below to revoke
access or grants for an OAuth consumer to act on your behalf.
+
+Note that if you authorized a consumer to only have access to a subset of
wikis (site projects), then there will be multiple access tokens for that
consumer.',
+ 'mwoauthmanagemygrants-confirm-legend' => 'Manage consumer access
token',
+ 'mwoauthmanagemygrants-update' => 'Update access token grants',
+ 'mwoauthmanagemygrants-renounce' => 'De-authorize and delete access
token',
+ 'mwoauthmanagemygrants-action' => 'Change status:',
+ 'mwoauthmanagemygrants-confirm-submit' => 'Update access token status',
+ 'mwoauthmanagemygrants-success-update' => 'The access token for this
consumer was successfully updated.',
+ 'mwoauthmanagemygrants-success-renounce' => 'The access token for this
consumer was successfully deleted.',
+
'mwoauth-logentry-consumer-propose' => 'proposed an OAuth consumer
(consumer key $2)',
'mwoauth-logentry-consumer-update' => 'updated an OAuth consumer
(consumer key $2)',
'mwoauth-logentry-consumer-approve' => 'approved an OAuth consumer by
$1 (consumer key $2)',
diff --git a/frontend/specialpages/actions/MWOAuthManageConsumers.php
b/frontend/specialpages/actions/MWOAuthManageConsumers.php
index d524b0c..267c214 100644
--- a/frontend/specialpages/actions/MWOAuthManageConsumers.php
+++ b/frontend/specialpages/actions/MWOAuthManageConsumers.php
@@ -76,8 +76,6 @@
break;
}
- $this->addQueueSubtitleLinks( $consumerKey );
-
if ( $this->stage !== null ) {
$this->stageKey = $stageKey;
if ( $consumerKey ) {
@@ -88,6 +86,8 @@
} else {
$this->showMainHub();
}
+
+ $this->addQueueSubtitleLinks( $consumerKey );
$this->getOutput()->addModules( 'ext.MWOAuth' ); // CSS
}
@@ -103,21 +103,21 @@
$listLinks = array();
if ( $consumerKey || $this->stage !==
MWOAuthConsumer::STAGE_PROPOSED ) {
$listLinks[] = Linker::linkKnown(
- SpecialPage::getSafeTitleFor(
'MWOAuthManageConsumers', 'proposed' ),
+ $this->getTitle( 'proposed' ),
$this->msg(
'mwoauthmanageconsumers-showproposed' )->escaped() );
} else {
$listLinks[] = $this->msg(
'mwoauthmanageconsumers-showproposed' )->escaped();
}
if ( $consumerKey || $this->stage !==
MWOAuthConsumer::STAGE_REJECTED ) {
$listLinks[] = Linker::linkKnown(
- SpecialPage::getSafeTitleFor(
'MWOAuthManageConsumers', 'rejected' ),
+ $this->getTitle( 'rejected' ),
$this->msg(
'mwoauthmanageconsumers-showrejected' )->escaped() );
} else {
$listLinks[] = $this->msg(
'mwoauthmanageconsumers-showrejected' )->escaped();
}
if ( $consumerKey || $this->stage !==
MWOAuthConsumer::STAGE_EXPIRED ) {
$listLinks[] = Linker::linkKnown(
- SpecialPage::getSafeTitleFor(
'MWOAuthManageConsumers', 'expired' ),
+ $this->getTitle( 'expired' ),
$this->msg(
'mwoauthmanageconsumers-showexpired' )->escaped() );
} else {
$listLinks[] = $this->msg(
'mwoauthmanageconsumers-showexpired' )->escaped();
@@ -128,15 +128,8 @@
$viewall = $this->msg( 'parentheses' )->rawParams(
Linker::linkKnown(
$this->getTitle(), $this->msg(
'mwoauthmanageconsumers-main' )->escaped() ) );
- // Give grep a chance to find the usages:
- // mwoauthmanageconsumers-type-proposed,
mwoauthmanageconsumers-type-reject,
- // mwoauthmanageconsumers-type-expired
$this->getOutput()->setSubtitle(
"<strong>" . $this->msg( 'mwoauthmanageconsumers-type'
)->escaped() . " <i>" .
- ( $this->stageKey !== null
- ? $this->msg(
"mwoauthmanageconsumers-type-{$this->stageKey}" )->escaped()
- : ''
- ) .
"</i></strong> [{$linkHtml}]
<strong>{$viewall}</strong>" );
}
@@ -171,7 +164,7 @@
'<li>' .
"<$tag>" .
Linker::makeKnownLinkObj(
- SpecialPage::getSafeTitleFor(
'MWOAuthManageConsumers', $stageKey ),
+ $this->getTitle( $stageKey ),
// Give grep a chance to find the
usages:
// mwoauthmanageconsumers-q-proposed,
mwoauthmanageconsumers-q-reject,
// mwoauthmanageconsumers-q-expired
@@ -189,7 +182,7 @@
$out->addHTML(
'<li>' .
Linker::makeKnownLinkObj(
- SpecialPage::getSafeTitleFor(
'MWOAuthManageConsumers', $stageKey ),
+ $this->getTitle( $stageKey ),
// Give grep a chance to find the
usages:
// mwoauthmanageconsumers-l-proposed,
mwoauthmanageconsumers-l-reject,
// mwoauthmanageconsumers-l-expired
@@ -243,6 +236,11 @@
'label-message' =>
'mwoauth-consumer-version',
'default' => $cmr->get( 'version' )
),
+ 'user' => array(
+ 'type' => 'info',
+ 'label-message' =>
'mwoauth-consumer-user',
+ 'default' => $cmr->get( 'userId',
array( 'User', 'whoIs' ) )
+ ),
'stage' => array(
'type' => 'info',
'label-message' =>
'mwoauth-consumer-stage',
@@ -286,6 +284,11 @@
'default' => $cmr->get( 'restrictions',
array( 'FormatJSON', 'encode' ) ),
'readonly' => true,
'rows' => 5
+ ),
+ 'secretKey' => array(
+ 'type' => 'info',
+ 'label-message' =>
'mwoauth-consumer-secretkey',
+ 'default' => $cmr->get( 'secretKey' )
),
'rsaKey' => array(
'type' => 'textarea',
@@ -335,6 +338,9 @@
$status = $form->show();
if ( $status instanceof Status && $status->isOk() ) {
$type =
self::$stageKeyMap[$status->value['result']->get( 'stage' )];
+ // Uses messages
mwoauthmanageconsumers-success-proposed,
+ // mwoauthmanageconsumers-success-rejected,
mwoauthmanageconsumers-success-approved,
+ // mwoauthmanageconsumers-success-disabled,
mwoauthmanageconsumers-success-reenabled
$this->getOutput()->addWikiMsg(
"mwoauthmanageconsumers-success-$type" );
$this->getOutput()->returnToMain();
} else {
@@ -392,7 +398,7 @@
$stageKey = self::$stageKeyMap[$cmr->get( 'stage' )];
$link = Linker::linkKnown(
- SpecialPage::getSafeTitleFor( 'MWOAuthManageConsumers',
"{$stageKey}/{$cmrKey}" ),
+ $this->getTitle( "{$stageKey}/{$cmrKey}" ),
$this->msg( 'mwoauthmanageconsumers-review' )->escaped()
);
diff --git a/frontend/specialpages/actions/MWOAuthManageMyGrants.php
b/frontend/specialpages/actions/MWOAuthManageMyGrants.php
new file mode 100644
index 0000000..b5d8064
--- /dev/null
+++ b/frontend/specialpages/actions/MWOAuthManageMyGrants.php
@@ -0,0 +1,368 @@
+<?php
+/*
+ (c) Aaron Schulz 2013, GPL
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ http://www.gnu.org/copyleft/gpl.html
+*/
+
+/**
+ * Special page for listing consumers this user granted access to and
+ * for manage the specific grants given or revoking access for the consumer
+ */
+class MWOAuthManageMyGrants extends UnlistedSpecialPage {
+ protected static $stageKeyMap = array(
+ MWOAuthConsumer::STAGE_PROPOSED => 'proposed',
+ MWOAuthConsumer::STAGE_REJECTED => 'rejected',
+ MWOAuthConsumer::STAGE_EXPIRED => 'expired',
+ MWOAuthConsumer::STAGE_APPROVED => 'approved',
+ MWOAuthConsumer::STAGE_DISABLED => 'disabled',
+ );
+
+ public function __construct() {
+ parent::__construct( 'MWOAuthManageMyGrants',
'mwoauthmanagemygrants' );
+ }
+
+ public function execute( $par ) {
+ $user = $this->getUser();
+ $request = $this->getRequest();
+
+ if ( !$user->isAllowed( 'mwoauthmanagemygrants' ) ) {
+ throw new PermissionsError( 'mwoauthmanagemygrants' );
+ } elseif ( !$user->getID() ) {
+ throw new PermissionsError( 'user' );
+ }
+
+ $this->setHeaders();
+ $this->getOutput()->disallowUserJs();
+
+ // Format is
Special:MWOAuthManageMyGrants[/list|/manage/<accesstoken>]
+ $navigation = explode( '/', $par );
+ $typeKey = isset( $navigation[0] ) ? $navigation[0] : null;
+ $accessToken = isset( $navigation[1] ) ? $navigation[1] : null;
+
+ switch ( $typeKey ) {
+ case 'manage':
+ $this->handleConsumerForm( $accessToken );
+ break;
+ case 'list':
+ // fall through
+ default:
+ $this->showConsumerList();
+ break;
+ }
+
+ $this->addSubtitleLinks( $accessToken );
+
+ $this->getOutput()->addModules( 'ext.MWOAuth' ); // CSS
+ }
+
+ /**
+ * Show other parent page link
+ *
+ * @param type $accessToken
+ * @return void
+ */
+ protected function addSubtitleLinks( $accessToken ) {
+ $listLinks = array();
+ if ( $accessToken ) {
+ $listLinks[] = Linker::linkKnown(
+ $this->getTitle( 'proposed' ),
+ $this->msg( 'mwoauthmanagemygrants-showlist'
)->escaped() );
+ } else {
+ $listLinks[] = $this->msg(
'mwoauthmanagemygrants-showlist' )->escaped();
+ }
+
+ $linkHtml = $this->getLanguage()->pipeList( $listLinks );
+
+ $this->getOutput()->setSubtitle(
+ "<strong>" . $this->msg(
'mwoauthmanagemygrants-navigation' )->escaped() .
+ "</strong> [{$linkHtml}]" );
+ }
+
+ /**
+ * Show the form to approve/reject/disable/re-enable consumers
+ *
+ * @param string $accessToken
+ * @return void
+ */
+ protected function handleConsumerForm( $accessToken ) {
+ $user = $this->getUser();
+ $db = MWOAuthUtils::getCentralDB( DB_SLAVE );
+
+ $cmra = MWOAuthDAOAccessControl::wrap(
+ MWOAuthConsumerAcceptance::newFromToken( $db,
$accessToken ), $this->getContext() );
+ if ( !$cmra ) {
+ $this->getOutput()->addHtml( $this->msg(
'mwoauth-invalid-access-token' )->escaped() );
+ return;
+ }
+
+ $cmr = MWOAuthDAOAccessControl::wrap(
+ MWOAuthConsumer::newFromId( $db, $cmra->get(
'consumerId' ) ), $this->getContext() );
+ if ( $cmr->get( 'deleted' ) && !$user->isAllowed(
'mwoauthviewsuppressed' ) ) {
+ throw new PermissionsError( 'mwoauthviewsuppressed' );
+ }
+
+ $form = new HTMLForm(
+ array(
+ 'accessToken' => array(
+ 'type' => 'text',
+ 'label-message' =>
'mwoauth-consumer-accesstoken',
+ 'default' => $cmra->get( 'accessToken'
),
+ 'size' => '40',
+ 'readonly' => true
+ ),
+ 'name' => array(
+ 'type' => 'info',
+ 'label-message' =>
'mwoauth-consumer-name',
+ 'default' => $cmr->get( 'name' )
+ ),
+ 'user' => array(
+ 'type' => 'info',
+ 'label-message' =>
'mwoauth-consumer-user',
+ 'default' => $cmr->get( 'userId',
array( 'User', 'whoIs' ) )
+ ),
+ 'version' => array(
+ 'type' => 'info',
+ 'label-message' =>
'mwoauth-consumer-version',
+ 'default' => $cmr->get( 'version' )
+ ),
+ 'consumerKey' => array(
+ 'type' => 'info',
+ 'label-message' =>
'mwoauth-consumer-key',
+ 'default' => $cmr->get( 'consumerKey' )
+ ),
+ 'description' => array(
+ 'type' => 'textarea',
+ 'label-message' =>
'mwoauth-consumer-description',
+ 'default' => $cmr->get( 'description' ),
+ 'readonly' => true,
+ 'rows' => 5
+ ),
+ 'grants' => array(
+ 'type' => 'checkmatrix',
+ 'label-message' =>
'mwoauthmanagemygrants-applicablegrantsallowed',
+ 'columns' => array(
+ $this->msg(
'mwoauthmanagemygrants-grantaccept' )->escaped() => 'grant'
+ ),
+ 'rows' => array_combine(
+ $cmr->get( 'grants' ), //
@TODO: use messages
+ $cmr->get( 'grants' )
+ ),
+ 'default' => array_map(
+ function( $g ) { return
"grant-$g"; },
+ $cmra->get( 'grants' )
+ )
+ // @TODO: tooltips
+ ),
+ 'usedOnWiki' => array(
+ 'type' => 'info',
+ 'label-message' =>
'mwoauth-consumer-wiki',
+ 'default' => $cmr->get( 'wiki' )
+ ),
+ 'wiki' => array(
+ 'type' => 'text',
+ 'label-message' =>
'mwoauthmanagemygrants-wikiallowed',
+ 'default' => $cmra->get( 'wiki' )
+ ),
+ 'action' => array(
+ 'type' => 'radio',
+ 'label-message' =>
'mwoauthmanagemygrants-action',
+ 'required' => true,
+ 'options' => array(
+ $this->msg(
'mwoauthmanagemygrants-update' )->escaped() => 'update',
+ $this->msg(
'mwoauthmanagemygrants-renounce' )->escaped() => 'renounce' )
+ )
+ ),
+ $this->getContext()
+ );
+ $act = null;
+ $form->setSubmitCallback( function( array $data, IContextSource
$context ) use ( &$act ) {
+ $act = $data['action']; // this will be valid on success
+ $data['grants'] = FormatJSON::encode( // adapt form to
controller
+ preg_replace( '/^grant-/', '', $data['grants']
) );
+ $controller = new
MWOAuthConsumerAcceptanceSubmitControl( $context, $data );
+ return $controller->submit();
+ } );
+
+ $form->setWrapperLegendMsg(
'mwoauthmanagemygrants-confirm-legend' );
+ $form->setSubmitTextMsg( 'mwoauthmanagemygrants-confirm-submit'
);
+ $form->addPreText(
+ $this->msg( 'mwoauthmanagemygrants-confirm-text'
)->parseAsBlock() );
+
+ $status = $form->show();
+ if ( $status instanceof Status && $status->isOk() ) {
+ // Uses messages mwoauthmanagemygrants-success-update,
+ // mwoauthmanagemygrants-success-renounce
+ $this->getOutput()->addWikiMsg(
"mwoauthmanagemygrants-success-$act" );
+ $this->getOutput()->returnToMain();
+ }
+ }
+
+ /**
+ * Show a paged list of consumers with links to details
+ *
+ * @param string $accessToken
+ * @return void
+ */
+ protected function showConsumerList() {
+ $out = $this->getOutput();
+
+ $pager = new MWOAuthManageMyGrantsPager( $this, array(),
$this->getUser()->getId() );
+
+ if ( $pager->getNumRows() ) {
+ $out->addHTML( $pager->getNavigationBar() );
+ $out->addHTML( $pager->getBody() );
+ $out->addHTML( $pager->getNavigationBar() );
+ } else {
+ $out->addWikiMsg( "mwoauthmanagemygrants-none" );
+ }
+ }
+
+ /**
+ * @param DatabaseBase $db
+ * @param sdtclass $row
+ * @return string
+ */
+ public function formatRow( $db, $row ) {
+ $cmr = MWOAuthDAOAccessControl::wrap(
+ MWOAuthConsumer::newFromRow( $db, $row ),
$this->getContext() );
+ $cmra = MWOAuthDAOAccessControl::wrap(
+ MWOAuthConsumerAcceptance::newFromRow( $db, $row ),
$this->getContext() );
+
+ $cmrKey = $cmr->get( 'consumerKey' );
+ $stageKey = self::$stageKeyMap[$cmr->get( 'stage' )];
+
+ $link = Linker::linkKnown(
+ $this->getTitle( 'manage/' . $cmra->get( 'accessToken'
) ),
+ $this->msg( 'mwoauthmanagemygrants-review' )->escaped()
+ );
+
+ $time = $this->getLanguage()->timeanddate(
+ wfTimestamp( TS_MW, $cmr->get( 'registration' ) ), true
);
+
+ $encStageKey = htmlspecialchars( $stageKey ); // sanity
+ $r = "<li
class='mw-mwoauthmanagemygrants-type-{$encStageKey}'>";
+
+ $r .= $time . " (<strong>{$link}</strong>)";
+
+ $lang = $this->getLanguage();
+ $data = array(
+ 'mwoauthmanagemygrants-name' =>
+ $cmr->get( 'name', function( $s ) use ( $cmr ) {
+ return $s . ' [' . $cmr->get( 'version'
) . ']'; } ),
+ 'mwoauthmanagemygrants-user' => $cmr->get( 'userId',
array( 'User', 'whoIs' ) ),
+ 'mwoauthmanagemygrants-description' =>
+ $cmr->get( 'description', function( $s ) use (
$lang ) {
+ return $lang->truncate( $s, 10024 ); }
),
+ 'mwoauthmanagemygrants-wiki' => $cmr->get( 'wiki' ),
+ 'mwoauthmanagemygrants-wikiallowed' => $cmra->get(
'wiki' ),
+ 'mwoauthmanagemygrants-grants' => $lang->commaList(
$cmr->get( 'grants' ) ),
+ 'mwoauthmanagemygrants-grantsallowed' =>
$lang->commaList( $cmra->get( 'grants' ) ),
+ 'mwoauthmanagemygrants-consumerkey' => $cmr->get(
'consumerKey' )
+ );
+
+ $r .= "<table
class='mw-mwoauthmanagemygrants-body-{$encStageKey}' " .
+ "cellspacing='1' cellpadding='3' border='1'
width='100%'>";
+ foreach ( $data as $msg => $value ) {
+ $r .= '<tr>' .
+ '<td><strong>' . $this->msg( $msg )->escaped()
. '</strong></td>' .
+ '<td width=\'90%\'>' . htmlspecialchars( $value
) . '</td>' .
+ '</tr>';
+ }
+ $r .= '</table>';
+
+ $r .= '</li>';
+
+ return $r;
+ }
+}
+
+/**
+ * Query to list out consumers that have an access token for this user
+ *
+ * @TODO: use UserCache
+ */
+class MWOAuthManageMyGrantsPager extends ReverseChronologicalPager {
+ public $mForm, $mConds;
+
+ function __construct( $form, $conds, $user ) {
+ $this->mForm = $form;
+ $this->mConds = $conds;
+
+ $this->mConds[] = 'oaac_consumer_id = oarc_id';
+ $this->mConds['oaac_user_id'] = $user;
+
+ parent::__construct();
+ # Treat 20 as the default limit, since each entry takes up 5
rows.
+ $urlLimit = $this->mRequest->getInt( 'limit' );
+ $this->mLimit = $urlLimit ? $urlLimit : 20;
+ }
+
+ /**
+ * @return Title
+ */
+ function getTitle() {
+ return $this->mForm->getFullTitle();
+ }
+
+ /**
+ * @param $row
+ * @return string
+ */
+ function formatRow( $row ) {
+ return $this->mForm->formatRow( $this->mDb, $row );
+ }
+
+ /**
+ * @return string
+ */
+ function getStartBody() {
+ if ( $this->getNumRows() ) {
+ return '<ul>';
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * @return string
+ */
+ function getEndBody() {
+ if ( $this->getNumRows() ) {
+ return '</ul>';
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * @return array
+ */
+ function getQueryInfo() {
+ return array(
+ 'tables' => array( 'oauth_accepted_consumer',
'oauth_registered_consumer' ),
+ 'fields' => array( '*' ),
+ 'conds' => $this->mConds
+ );
+ }
+
+ /**
+ * @return string
+ */
+ function getIndexField() {
+ return 'oaac_accepted';
+ }
+}
--
To view, visit https://gerrit.wikimedia.org/r/72990
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I669bd4b750cdfafd18dad60d8cdabdc1675113f4
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/OAuth
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
Gerrit-Reviewer: CSteipp <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits