diff --git a/ApiVoteNY.php b/ApiVoteNY.php new file mode 100644 index 0000000..90d5e00 --- /dev/null +++ b/ApiVoteNY.php @@ -0,0 +1,143 @@ +getUser(); + + // Get the request parameters + $params = $this->extractRequestParams(); + + $action = $params['what']; + + // If the "what" param isn't present, we don't know what to do! + if ( !$action || $action === null ) { + $this->dieUsageMsg( 'missingparam' ); + } + + // Need to have sufficient user rights to proceed... + if ( !$user->isAllowed( 'voteny' ) ) { + $this->dieUsageMsg( 'badaccess-group0' ); + } + + // Ensure that the page ID is present and that it really is numeric + $pageId = $params['pageId']; + + if ( !$pageId || $pageId === null || !is_numeric( $pageId ) ) { + $this->dieUsageMsg( array( 'missingparam', 'pageId' ) ); + } + + // Vote value is needed for actual vote actions, i.e. everything but "delete" + $voteValue = $params['voteValue']; + + if ( !( $voteValue || $voteValue === null ) && $action !== 'delete' ) { + $this->dieUsageMsg( array( 'missingparam', 'voteValue' ) ); + } + + // Set the private class member variable and do something... + if ( isset( $params['type'] ) && $params['type'] && $params['type'] == 'stars' ) { + $this->vote = new VoteStars( $pageId ); + + switch ( $action ) { + case 'delete': + $this->vote->delete(); + $output = $this->vote->display(); + break; + case 'multi': + if ( $this->vote->UserAlreadyVoted() ) { + $this->vote->delete(); + } + $this->vote->insert( $voteValue ); + $output = $this->vote->displayScore(); + break; + case 'vote': + default: + if ( $this->vote->UserAlreadyVoted() ) { + $this->vote->delete(); + } + $this->vote->insert( $voteValue ); + $output = $this->vote->display( $voteValue ); + break; + } + } else { + $this->vote = new Vote( $pageId ); + + switch ( $action ) { + case 'delete': + $this->vote->delete(); + $output = $this->vote->count( 1 ); + break; + case 'vote': + default: + $this->vote->insert( $voteValue ); + $output = $this->vote->count( 1 ); + break; + } + } + + // Top level + $this->getResult()->addValue( null, $this->getModuleName(), + array( 'result' => $output ) + ); + + return true; + } + + public function needsToken() { + return 'csrf'; + } + + public function isWriteMode() { + return true; + } + + /** + * @return array + */ + public function getAllowedParams() { + return array( + 'what' => array( + ApiBase::PARAM_TYPE => 'string', + ApiBase::PARAM_REQUIRED => true + ), + 'pageId' => array( + ApiBase::PARAM_TYPE => 'integer', + ApiBase::PARAM_REQUIRED => true + ), + 'voteValue' => array( + ApiBase::PARAM_TYPE => 'integer', + ), + 'type' => array( + ApiBase::PARAM_TYPE => 'string', + ) + ); + } + + /** + * @see ApiBase::getExamplesMessages() + */ + protected function getExamplesMessages() { + return array( + 'action=voteny&what=vote&pageId=666' => 'apihelp-voteny-example-1', + 'action=voteny&what=delete&pageId=666' => 'apihelp-voteny-example-2', + 'action=voteny&what=vote&type=stars&pageId=666&voteValue=3' => 'apihelp-voteny-example-3', + 'action=voteny&what=delete&type=stars&pageId=666' => 'apihelp-voteny-example-4', + 'action=voteny&what=multi&type=stars&pageId=666&voteValue=4' => 'apihelp-voteny-example-5' + ); + } +} diff --git a/Vote.js b/Vote.js index 09444da..859bf76 100644 --- a/Vote.js +++ b/Vote.js @@ -25,14 +25,14 @@ var VoteNY = function VoteNY() { * @param PageID Integer: internal ID number of the current article */ this.clickVote = function( TheVote, PageID ) { - $.post( - mw.util.wikiScript(), { - action: 'ajax', - rs: 'wfVoteClick', - rsargs: [ TheVote, PageID ] - } - ).done( function( data ) { - $( '#PollVotes' ).html( ( data || '0' ) ); + ( new mw.Api() ).postWithToken( 'csrf', { + action: 'voteny', + format: 'json', + what: 'vote', + pageId: PageID, + voteValue: TheVote + } ).done( function( data ) { + $( '#PollVotes' ).html( data.voteny.result ); $( '#Answer' ).html( '' + mediaWiki.msg( 'voteny-unvote-link' ) + '' @@ -44,17 +44,15 @@ var VoteNY = function VoteNY() { * Called when removing your vote through the green square voting box * * @param PageID Integer: internal ID number of the current article - * @param mk Mixed: random token */ this.unVote = function( PageID ) { - $.post( - mw.util.wikiScript(), { - action: 'ajax', - rs: 'wfVoteDelete', - rsargs: [ PageID ] - } - ).done( function( data ) { - $( '#PollVotes' ).html( ( data || '0' ) ); + ( new mw.Api() ).postWithToken( 'csrf', { + action: 'voteny', + format: 'json', + what: 'delete', + pageId: PageID + } ).done( function( data ) { + $( '#PollVotes' ).html( data.voteny.result ); $( '#Answer' ).html( '' + mediaWiki.msg( 'voteny-link' ) + '' @@ -71,22 +69,22 @@ var VoteNY = function VoteNY() { */ this.clickVoteStars = function( TheVote, PageID, id, action ) { this.voted_new[id] = TheVote; - var rsfun; + var actionName; if ( action == 3 ) { - rsfun = 'wfVoteStars'; + actionName = 'stars'; // all other values but 'multi' are ignored anyway } if ( action == 5 ) { - rsfun = 'wfVoteStarsMulti'; + actionName = 'multi'; } - $.post( - mw.util.wikiScript(), { - action: 'ajax', - rs: rsfun, - rsargs: [ TheVote, PageID ] - } - ).done( function( data ) { - $( '#rating_' + id ).html( data ); + ( new mw.Api() ).postWithToken( 'csrf', { + action: 'voteny', + type: 'stars', + what: actionName, + voteValue: TheVote, + pageId: PageID + } ).done( function( data ) { + $( '#rating_' + id ).html( data.voteny.result ); } ); }; @@ -97,14 +95,13 @@ var VoteNY = function VoteNY() { * @param id Integer: ID of the current rating star */ this.unVoteStars = function( PageID, id ) { - $.post( - mw.util.wikiScript(), { - action: 'ajax', - rs: 'wfVoteStarsDelete', - rsargs: [ PageID ] - } - ).done( function( data ) { - $( '#rating_' + id ).html( data ); + ( new mw.Api() ).postWithToken( 'csrf', { + action: 'voteny', + what: 'delete', + type: 'stars', + pageId: PageID + } ).done( function( data ) { + $( '#rating_' + id ).html( data.voteny.result ); } ); }; diff --git a/Vote.php b/Vote.php deleted file mode 100644 index 8aa3279..0000000 --- a/Vote.php +++ /dev/null @@ -1,4 +0,0 @@ -display(); } - wfProfileOut( __METHOD__ ); - return $output; } @@ -174,7 +170,7 @@ class VoteHooks { * @param string $pagename Page name * @return int Amount of votes for the given page */ - static function getNumberOfVotesPageParser( $parser, $pagename ) { + public static function getNumberOfVotesPageParser( $parser, $pagename ) { $title = Title::newFromText( $pagename ); if ( !$title instanceof Title ) { @@ -202,7 +198,7 @@ class VoteHooks { * @param Parser $parser * @return bool */ - static function setupNumberOfVotesPageParser( &$parser ) { + public static function setupNumberOfVotesPageParser( &$parser ) { $parser->setFunctionHook( 'NUMBEROFVOTESPAGE', 'VoteHooks::getNumberOfVotesPageParser', Parser::SFH_NO_HASH ); return true; } diff --git a/VoteNY.php b/VoteNY.php deleted file mode 100644 index f5c0f45..0000000 --- a/VoteNY.php +++ /dev/null @@ -1,70 +0,0 @@ - tag - * - * @file - * @ingroup Extensions - * @author Aaron Wright - * @author David Pean - * @author Jack Phoenix - * @link https://www.mediawiki.org/wiki/Extension:VoteNY Documentation - * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later - */ - -// Extension credits that show up on Special:Version -$wgExtensionCredits['parserhook'][] = array( - 'name' => 'Vote', - 'version' => '2.7', - 'author' => array( 'Aaron Wright', 'David Pean', 'Jack Phoenix' ), - 'descriptionmsg' => 'voteny-desc', - 'url' => 'https://www.mediawiki.org/wiki/Extension:VoteNY' -); - -// Path to Vote extension files -$wgVoteDirectory = "$IP/extensions/VoteNY"; - -// New user right -$wgAvailableRights[] = 'voteny'; -$wgGroupPermissions['*']['voteny'] = false; // Anonymous users cannot vote -$wgGroupPermissions['user']['voteny'] = true; // Registered users can vote - -// AJAX functions needed by this extension -require_once 'Vote_AjaxFunctions.php'; - -// Autoload classes and set up i18n -$wgMessagesDirs['VoteNY'] = __DIR__ . '/i18n'; -$wgExtensionMessagesFiles['VoteNYAlias'] = __DIR__ . '/VoteNY.alias.php'; -$wgExtensionMessagesFiles['VoteNYMagic'] = __DIR__ . '/VoteNY.i18n.magic.php'; - -$wgAutoloadClasses['Vote'] = __DIR__ . '/VoteClass.php'; -$wgAutoloadClasses['VoteStars'] = __DIR__ . '/VoteClass.php'; - -// Set up the new special page, Special:TopRatings, which shows top rated pages -// based on given criteria -$wgAutoloadClasses['SpecialTopRatings'] = __DIR__ . '/SpecialTopRatings.php'; -$wgSpecialPages['TopRatings'] = 'SpecialTopRatings'; - -// Hooked functions -$wgAutoloadClasses['VoteHooks'] = __DIR__ . '/VoteHooks.php'; - -$wgHooks['ParserFirstCallInit'][] = 'VoteHooks::registerParserHook'; -$wgHooks['RenameUserSQL'][] = 'VoteHooks::onUserRename'; -$wgHooks['ParserGetVariableValueSwitch'][] = 'VoteHooks::assignValueToMagicWord'; -$wgHooks['MagicWordwgVariableIDs'][] = 'VoteHooks::registerVariableId'; -$wgHooks['ParserFirstCallInit'][] = 'VoteHooks::setupNumberOfVotesPageParser'; -$wgHooks['LoadExtensionSchemaUpdates'][] = 'VoteHooks::addTable'; - -// ResourceLoader support for MediaWiki 1.17+ -$wgResourceModules['ext.voteNY.styles'] = array( - 'styles' => 'Vote.css', - 'localBasePath' => __DIR__, - 'remoteExtPath' => 'VoteNY', - 'position' => 'top' // available since r85616 -); - -$wgResourceModules['ext.voteNY.scripts'] = array( - 'scripts' => 'Vote.js', - 'messages' => array( 'voteny-link', 'voteny-unvote-link' ), - 'localBasePath' => __DIR__, - 'remoteExtPath' => 'VoteNY' -); diff --git a/Vote_AjaxFunctions.php b/Vote_AjaxFunctions.php deleted file mode 100644 index f838b18..0000000 --- a/Vote_AjaxFunctions.php +++ /dev/null @@ -1,88 +0,0 @@ -isAllowed( 'voteny' ) ) { - return ''; - } - - if ( is_numeric( $pageId ) && ( is_numeric( $voteValue ) ) ) { - $vote = new Vote( $pageId ); - $vote->insert( $voteValue ); - - return $vote->count( 1 ); - } else { - return 'error'; - } -} - -$wgAjaxExportList[] = 'wfVoteDelete'; -function wfVoteDelete( $pageId ) { - global $wgUser; - - if ( !$wgUser->isAllowed( 'voteny' ) ) { - return ''; - } - - if ( is_numeric( $pageId ) ) { - $vote = new Vote( $pageId ); - $vote->delete(); - - return $vote->count( 1 ); - } else { - return 'error'; - } -} - -$wgAjaxExportList[] = 'wfVoteStars'; -function wfVoteStars( $voteValue, $pageId ) { - global $wgUser; - - if ( !$wgUser->isAllowed( 'voteny' ) ) { - return ''; - } - - $vote = new VoteStars( $pageId ); - if ( $vote->UserAlreadyVoted() ) { - $vote->delete(); - } - $vote->insert( $voteValue ); - - return $vote->display( $voteValue ); -} - -$wgAjaxExportList[] = 'wfVoteStarsMulti'; -function wfVoteStarsMulti( $voteValue, $pageId ) { - global $wgUser; - - if ( !$wgUser->isAllowed( 'voteny' ) ) { - return ''; - } - - $vote = new VoteStars( $pageId ); - if ( $vote->UserAlreadyVoted() ) { - $vote->delete(); - } - $vote->insert( $voteValue ); - - return $vote->displayScore(); -} - -$wgAjaxExportList[] = 'wfVoteStarsDelete'; -function wfVoteStarsDelete( $pageId ) { - global $wgUser; - - if ( !$wgUser->isAllowed( 'voteny' ) ) { - return ''; - } - - $vote = new VoteStars( $pageId ); - $vote->delete(); - - return $vote->display(); -} diff --git a/extension.json b/extension.json new file mode 100644 index 0000000..82ed752 --- /dev/null +++ b/extension.json @@ -0,0 +1,84 @@ +{ + "name": "VoteNY", + "version": "2.8", + "author": [ + "Aaron Wright", + "David Pean", + "Jack Phoenix" + ], + "license-name": "GPL-2.0+", + "url": "https://www.mediawiki.org/wiki/Extension:VoteNY", + "descriptionmsg": "voteny-desc", + "type": "parserhook", + "SpecialPages": { + "TopRatings": "SpecialTopRatings" + }, + "MessagesDirs": { + "VoteNY": [ + "i18n" + ] + }, + "APIModules": { + "voteny": "ApiVoteNY" + }, + "ExtensionMessagesFiles": { + "VoteNYAlias": "VoteNY.alias.php", + "VoteNYMagic": "VoteNY.i18n.magic.php" + }, + "AutoloadClasses": { + "ApiVoteNY": "ApiVoteNY.php", + "Vote": "VoteClass.php", + "VoteStars": "VoteClass.php", + "SpecialTopRatings": "SpecialTopRatings.php", + "VoteHooks": "VoteHooks.php" + }, + "Hooks": { + "ParserFirstCallInit": [ + "VoteHooks::registerParserHook", + "VoteHooks::setupNumberOfVotesPageParser" + ], + "RenameUserSQL": [ + "VoteHooks::onUserRename" + ], + "ParserGetVariableValueSwitch": [ + "VoteHooks::assignValueToMagicWord" + ], + "MagicWordwgVariableIDs": [ + "VoteHooks::registerVariableId" + ], + "LoadExtensionSchemaUpdates": [ + "VoteHooks::addTable" + ] + }, + "ResourceFileModulePaths": { + "localBasePath": "", + "remoteExtPath": "VoteNY" + }, + "ResourceModules": { + "ext.voteNY.scripts": { + "scripts": "Vote.js", + "messages": [ + "voteny-link", + "voteny-unvote-link" + ], + "dependencies": [ "mediawiki.api" ], + "position": "bottom" + }, + "ext.voteNY.styles": { + "styles": "Vote.css", + "position": "top" + } + }, + "AvailableRights": [ + "voteny" + ], + "GroupPermissions": { + "*": { + "voteny": false + }, + "user": { + "voteny": true + } + }, + "manifest_version": 1 +} diff --git a/i18n/en.json b/i18n/en.json index a2d4ce0..7f9110f 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -5,6 +5,16 @@ "David Pean " ] }, + "apihelp-voteny-description": "VoteNY API module", + "apihelp-voteny-param-what": "Action to take; valid values are 'vote' (green voting box), 'multi' (voting stars) or 'delete' (delete a previously given vote)", + "apihelp-voteny-param-pageId": "Page ID of the page where the voting box/stars is/are", + "apihelp-voteny-param-voteValue": "Numerical vote value between 1 and 5", + "apihelp-voteny-param-type": "Set this to 'stars' to call the voting stars (VoteStars PHP class), otherwise the green vote box (Vote PHP class) is used", + "apihelp-voteny-example-1": "Cast a vote for the page which has the ID number 666", + "apihelp-voteny-example-2": "Delete your vote from the page which has the ID number 666", + "apihelp-voteny-example-3": "Cast a vote (3 stars out of 5) for the page which has the ID number 666", + "apihelp-voteny-example-4": "Delete your vote from the page which has the ID number 666 which is using the star rating", + "apihelp-voteny-example-5": "Cast a vote (4 stars out of 5) for the page which has the ID number 666, deleting your previous vote, if any", "voteny-desc": "JavaScript-based voting with the <vote> tag", "voteny-link": "Vote", "voteny-unvote-link": "unvote",