phase II social tools: VoteNY. Tested and built against MW 1.16.0. Can be used without the core social tools package (SocialProfile extension).
This commit is contained in:
commit
ae507a6ca3
|
@ -0,0 +1,185 @@
|
|||
<?php
|
||||
/**
|
||||
* A special page to display the highest rated pages on the wiki.
|
||||
*
|
||||
* This special page supports filtering by category and namespace, so
|
||||
* {{Special:TopRatings/Adventure Games/0/10}} will show 10 ratings where the
|
||||
* pages are in the "Adventure Games" category and the pages are in the main
|
||||
* (0) namespace.
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
* @date 21 August 2011
|
||||
* @license To the extent that it is possible, this code is in the public domain
|
||||
*/
|
||||
class SpecialTopRatings extends IncludableSpecialPage {
|
||||
|
||||
/**
|
||||
* Constructor -- set up the new special page
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct( 'TopRatings' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the special page
|
||||
*
|
||||
* @param $par Mixed: parameter passed to the special page or null
|
||||
*/
|
||||
public function execute( $par ) {
|
||||
global $wgOut, $wgScriptPath, $wgUser;
|
||||
|
||||
// Set the page title, robot policies, etc.
|
||||
$this->setHeaders();
|
||||
|
||||
$categoryName = $namespace = '';
|
||||
|
||||
// Parse the parameters passed to the special page
|
||||
// Make sure that the limit parameter passed to the special page is
|
||||
// an integer and that it's less than 100 (performance!)
|
||||
if ( isset( $par ) && is_numeric( $par ) && $par < 100 ) {
|
||||
$limit = intval( $par );
|
||||
} elseif ( isset( $par ) && !is_numeric( $par ) ) {
|
||||
// $par is a string...assume that we can explode() it
|
||||
$exploded = explode( '/', $par );
|
||||
$categoryName = $exploded[0];
|
||||
$namespace = ( isset( $exploded[1] ) ? intval( $exploded[1] ) : $namespace );
|
||||
$limit = ( isset( $exploded[2] ) ? intval( $exploded[2] ) : 50 );
|
||||
} else {
|
||||
$limit = 50;
|
||||
}
|
||||
|
||||
// Add JS -- needed so that users can vote on this page and so that
|
||||
// their browsers' consoles won't be filled with JS errors ;-)
|
||||
$wgOut->addScriptFile( $wgScriptPath . '/extensions/VoteNY/Vote.js' );
|
||||
|
||||
$ratings = array();
|
||||
$output = '';
|
||||
$sk = $wgUser->getSkin();
|
||||
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$tables = $where = $joinConds = array();
|
||||
$whatToSelect = array( 'DISTINCT vote_page_id' );
|
||||
|
||||
// By default we have no category and no namespace
|
||||
$tables = array( 'Vote' );
|
||||
$where = array( 'vote_page_id <> 0' );
|
||||
|
||||
// isset(), because 0 is a totally valid NS
|
||||
if ( !empty( $categoryName ) && isset( $namespace ) ) {
|
||||
$tables = array( 'Vote', 'page', 'categorylinks' );
|
||||
$where = array(
|
||||
'vote_page_id <> 0',
|
||||
'cl_to' => str_replace( ' ', '_', $categoryName ),
|
||||
'page_namespace' => $namespace
|
||||
);
|
||||
$joinConds = array(
|
||||
'categorylinks' => array( 'INNER JOIN', 'cl_from = page_id' ),
|
||||
'page' => array( 'INNER JOIN', 'page_id = vote_page_id' )
|
||||
);
|
||||
}
|
||||
|
||||
// Perform the SQL query with the given conditions; the basic idea is
|
||||
// that we get $limit (however, 100 or less) unique page IDs from the
|
||||
// Vote table. If a category and a namespace have been given, we also
|
||||
// do an INNER JOIN with page and categorylinks table to get the
|
||||
// correct data.
|
||||
$res = $dbr->select(
|
||||
$tables,
|
||||
$whatToSelect,
|
||||
$where,
|
||||
__METHOD__,
|
||||
array( 'LIMIT' => intval( $limit ) ),
|
||||
$joinConds
|
||||
);
|
||||
|
||||
foreach ( $res as $row ) {
|
||||
// Add the results to the $ratings array and get the amount of
|
||||
// votes the given page ID has
|
||||
// For example: $ratings[1] = 11 = page with the page ID 1 has 11
|
||||
// votes
|
||||
$ratings[$row->vote_page_id] = (int)$dbr->selectField(
|
||||
'Vote',
|
||||
'SUM(vote_value)',
|
||||
array( 'vote_page_id' => $row->vote_page_id ),
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
// If we have some ratings, start building HTML output
|
||||
if ( !empty( $ratings ) ) {
|
||||
/* XXX dirrrrrrty hack! because when we include this page, the JS
|
||||
is not included, but we want things to work still */
|
||||
if ( $this->including() ) {
|
||||
$output .= '<script type="text/javascript" src="' .
|
||||
$wgScriptPath . '/extensions/VoteNY/Vote.js"></script>';
|
||||
}
|
||||
|
||||
// yes, array_keys() is needed
|
||||
foreach ( array_keys( $ratings ) as $discardThis => $pageId ) {
|
||||
$titleObj = Title::newFromId( $pageId );
|
||||
if ( !( $titleObj instanceof Title ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$vote = new VoteStars( $pageId );
|
||||
$output .= '<div class="user-list-rating">' .
|
||||
$sk->link(
|
||||
$titleObj,
|
||||
$titleObj->getPrefixedText() // prefixed, so that the namespace shows!
|
||||
) . wfMsg( 'word-separator' ) . // i18n overkill? ya betcha...
|
||||
wfMsg( 'parentheses', $ratings[$pageId] ) .
|
||||
'</div>';
|
||||
|
||||
$id = mt_rand(); // AFAIK these IDs are and originally were totally random...
|
||||
$output .= "<div id=\"rating_stars_{$id}\">" .
|
||||
$vote->displayStars(
|
||||
$id,
|
||||
self::getAverageRatingForPage( $pageId ),
|
||||
false
|
||||
) . '</div>';
|
||||
$output .= "<div id=\"rating_{$id}\" class=\"rating-total\">" .
|
||||
$vote->displayScore() .
|
||||
'</div>';
|
||||
}
|
||||
} else {
|
||||
// Nothing? Well, display an informative error message rather than
|
||||
// a blank page or somesuch.
|
||||
$output .= wfMsg( 'topratings-no-pages' );
|
||||
}
|
||||
|
||||
// Output everything!
|
||||
$wgOut->addHTML( $output );
|
||||
}
|
||||
|
||||
/**
|
||||
* Static version of Vote::getAverageVote().
|
||||
*
|
||||
* @param $pageId Integer: ID of the page for which we want to get the avg.
|
||||
* rating
|
||||
* @return Integer: average vote for the given page (ID)
|
||||
*/
|
||||
public static function getAverageRatingForPage( $pageId ) {
|
||||
global $wgMemc;
|
||||
|
||||
$key = wfMemcKey( 'vote', 'avg', $pageId );
|
||||
$data = $wgMemc->get( $key );
|
||||
$voteAvg = 0;
|
||||
|
||||
if( $data ) {
|
||||
wfDebug( "Loading vote avg for page {$pageId} from cache (TopRatings)\n" );
|
||||
$voteAvg = $data;
|
||||
} else {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$voteAvg = (int)$dbr->selectField(
|
||||
'Vote',
|
||||
'AVG(vote_value) AS VoteAvg',
|
||||
array( 'vote_page_id' => $pageId ),
|
||||
__METHOD__
|
||||
);
|
||||
$wgMemc->set( $key, $voteAvg );
|
||||
}
|
||||
|
||||
return $voteAvg;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/* CSS for Vote extension */
|
||||
.vote-box {
|
||||
background-color: #68BD46;
|
||||
height: 30px;
|
||||
padding: 13px 0px 0px;
|
||||
text-align: center;
|
||||
width: 43px;
|
||||
}
|
||||
|
||||
.vote-number {
|
||||
color: #FFF;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.vote-action {
|
||||
text-align: center;
|
||||
width: 43px;
|
||||
}
|
||||
|
||||
.vote-action a {
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.rating-score {
|
||||
background-color: #68BD46;
|
||||
color: #FFF;
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
padding: 1px 8px 0px;
|
||||
margin: 1px 7px 0px 0px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ratings-top {
|
||||
position: absolute;
|
||||
top: 37px !important;
|
||||
right: 0px !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.rating-section img {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
|
||||
.rating-voted {
|
||||
color: #666666;
|
||||
line-height: 10px;
|
||||
font-size: 9px;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
/* Styling for the (n votes) after rating box/stars */
|
||||
.rating-total {
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
margin: 3px 0px 0px 0px;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
/**
|
||||
* Internationalization file for the Vote extension.
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
*/
|
||||
|
||||
$messages = array();
|
||||
|
||||
/** English
|
||||
* @author Aaron Wright <aaron.wright@gmail.com>
|
||||
* @author David Pean <david.pean@gmail.com>
|
||||
*/
|
||||
$messages['en'] = array(
|
||||
'vote-link' => 'Vote',
|
||||
'vote-unvote-link' => 'unvote',
|
||||
'vote-community-score' => 'community score: $1',
|
||||
'vote-ratings' => '{{PLURAL:$1|one rating|$1 ratings}}',
|
||||
'vote-remove' => 'remove',
|
||||
'vote-gave-this' => 'you gave this a $1',
|
||||
'vote-votes' => '{{PLURAL:$1|one vote|$1 votes}}',
|
||||
// Special:TopRatings
|
||||
'topratings' => 'Top rated pages',
|
||||
'topratings-no-pages' => 'No top rated pages.',
|
||||
// For Special:ListGroupRights
|
||||
'right-vote' => 'Vote pages',
|
||||
);
|
||||
|
||||
/** Finnish (Suomi)
|
||||
* @author Jack Phoenix <jack@countervandalism.net>
|
||||
*/
|
||||
$messages['fi'] = array(
|
||||
'vote-link' => 'Äänestä',
|
||||
'vote-unvote-link' => 'poista ääni',
|
||||
'vote-community-score' => 'yhteisön antama pistemäärä: $1',
|
||||
'vote-ratings' => '{{PLURAL:$1|yksi arvostelu|$1 arvostelua}}',
|
||||
'vote-remove' => 'poista',
|
||||
'vote-gave-this' => 'annoit tälle {{PLURAL:$1|yhden tähden|$1 tähteä}}',
|
||||
'vote-votes' => '{{PLURAL:$1|yksi ääni|$1 ääntä}}',
|
||||
'topratings' => 'Huippusivut',
|
||||
'topratings-no-pages' => 'Ei huippusivuja.',
|
||||
'right-vote' => 'Äänestää sivuja',
|
||||
);
|
||||
|
||||
/** French (Français)
|
||||
* @author Jack Phoenix <jack@countervandalism.net>
|
||||
*/
|
||||
$messages['fr'] = array(
|
||||
'vote-link' => 'Voter',
|
||||
'vote-unvote-link' => 'supprimer vote',
|
||||
'vote-remove' => 'supprimer',
|
||||
'vote-votes' => '{{PLURAL:$1|un vote|$1 votes}}',
|
||||
'right-vote' => 'Voter pages',
|
||||
);
|
||||
|
||||
/** Dutch (Nederlands)
|
||||
* @author Mitchel Corstjens
|
||||
*/
|
||||
$messages['nl'] = array(
|
||||
'vote-link' => 'Stem',
|
||||
'vote-unvote-link' => 'stem terugtrekken',
|
||||
'vote-community-score' => 'gemeenschap score: $1',
|
||||
'vote-remove' => 'verwijder',
|
||||
'vote-gave-this' => 'je gaf dit een $1',
|
||||
'vote-votes' => '{{PLURAL:$1|een stem|$1 stemmen}}',
|
||||
'topratings' => 'Meest gewaardeerde pagina\'s',
|
||||
'topratings-no-pages' => 'Er zijn nog geen meest gewaardeerde pagina\'s',
|
||||
'right-vote' => 'Stem paginas',
|
||||
);
|
||||
|
||||
/** Polish (Polski)
|
||||
* @author Misiek95
|
||||
*/
|
||||
$messages['pl'] = array(
|
||||
'vote-link' => 'Głosuj',
|
||||
'vote-unvote-link' => 'Anuluj',
|
||||
'vote-community-score' => 'Wynik wśród społeczności: $1',
|
||||
'vote-ratings' => '{{PLURAL:$1|1 głos|$1 głosy|$1 głosów}}',
|
||||
'vote-remove' => 'usuń',
|
||||
'vote-gave-this' => 'Oceniłeś to na $1',
|
||||
'vote-votes' => '{{PLURAL:$1|1 głos|$1 głosy|$1 głosów}}',
|
||||
'right-vote' => 'Udział w głosowaniach',
|
||||
);
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* JavaScript functions for Vote extension
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
* @author Jack Phoenix <jack@countervandalism.net>
|
||||
* @date 19 June 2011
|
||||
*/
|
||||
var VoteNY = {
|
||||
MaxRating: 5,
|
||||
clearRatingTimer: '',
|
||||
voted_new: [],
|
||||
id: 0,
|
||||
last_id: 0,
|
||||
imagePath: wgScriptPath + '/extensions/VoteNY/images/',
|
||||
|
||||
/**
|
||||
* Called when voting through the green square voting box
|
||||
* @param TheVote
|
||||
* @param PageID Integer: internal ID number of the current article
|
||||
* @param mk Mixed: random token
|
||||
*/
|
||||
clickVote: function( TheVote, PageID, mk ) {
|
||||
sajax_request_type = 'POST';
|
||||
sajax_do_call( 'wfVoteClick', [ TheVote, PageID, mk ], function( request ) {
|
||||
document.getElementById( 'votebox' ).style.cursor = 'default';
|
||||
document.getElementById( 'PollVotes' ).innerHTML = request.responseText;
|
||||
var unvoteMessage;
|
||||
if ( typeof( mediaWiki ) == 'undefined' ) {
|
||||
unvoteMessage = _UNVOTE_LINK;
|
||||
} else {
|
||||
unvoteMessage = mediaWiki.msg( 'vote-unvote-link' );
|
||||
}
|
||||
document.getElementById( 'Answer' ).innerHTML =
|
||||
"<a href=javascript:VoteNY.unVote(" + PageID + ",'" + mk +
|
||||
"')>" + unvoteMessage + '</a>';
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
unVote: function( PageID, mk ) {
|
||||
sajax_request_type = 'POST';
|
||||
sajax_do_call( 'wfVoteDelete', [ PageID, mk ], function( request ) {
|
||||
document.getElementById( 'votebox' ).style.cursor = 'pointer';
|
||||
document.getElementById( 'PollVotes' ).innerHTML = request.responseText;
|
||||
var voteMessage;
|
||||
if ( typeof( mediaWiki ) == 'undefined' ) {
|
||||
voteMessage = _VOTE_LINK;
|
||||
} else {
|
||||
voteMessage = mediaWiki.msg( 'vote-link' );
|
||||
}
|
||||
document.getElementById( 'Answer' ).innerHTML =
|
||||
'<a href=javascript:VoteNY.clickVote(1,' + PageID + ',"' + mk +
|
||||
'")>' + voteMessage + '</a>';
|
||||
} );
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when adding a vote after a user has clicked the yellow voting stars
|
||||
* @param PageID Integer: internal ID number of the current article
|
||||
* @param mk Mixed: random token
|
||||
* @param id Integer: ID of the current rating star
|
||||
* @param action Integer: controls which AJAX function will be called
|
||||
*/
|
||||
clickVoteStars: function( TheVote, PageID, mk, id, action ) {
|
||||
VoteNY.voted_new[id] = TheVote;
|
||||
var rsfun;
|
||||
if( action == 3 ) {
|
||||
rsfun = 'wfVoteStars';
|
||||
}
|
||||
if( action == 5 ) {
|
||||
rsfun = 'wfVoteStarsMulti';
|
||||
}
|
||||
|
||||
var resultElement = document.getElementById( 'rating_' + id );
|
||||
sajax_request_type = 'POST';
|
||||
sajax_do_call( rsfun, [ TheVote, PageID, mk ], resultElement );
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when removing your vote through the yellow voting stars
|
||||
* @param PageID Integer: internal ID number of the current article
|
||||
* @param mk Mixed: random token
|
||||
* @param id Integer: ID of the current rating star
|
||||
*/
|
||||
unVoteStars: function( PageID, mk, id ) {
|
||||
var resultElement = document.getElementById( 'rating_' + id );
|
||||
sajax_request_type = 'POST';
|
||||
sajax_do_call( 'wfVoteStarsDelete', [ PageID, mk ], resultElement );
|
||||
},
|
||||
|
||||
startClearRating: function( id, rating, voted ) {
|
||||
VoteNY.clearRatingTimer = setTimeout(
|
||||
"VoteNY.clearRating('" + id + "',0," + rating + ',' + voted + ')',
|
||||
200
|
||||
);
|
||||
},
|
||||
|
||||
clearRating: function( id, num, prev_rating, voted ) {
|
||||
if( VoteNY.voted_new[id] ) {
|
||||
voted = VoteNY.voted_new[id];
|
||||
}
|
||||
|
||||
for( var x = 1; x <= VoteNY.MaxRating; x++ ) {
|
||||
var star_on, old_rating;
|
||||
if( voted ) {
|
||||
star_on = 'voted';
|
||||
old_rating = voted;
|
||||
} else {
|
||||
star_on = 'on';
|
||||
old_rating = prev_rating;
|
||||
}
|
||||
var ratingElement = document.getElementById( 'rating_' + id + '_' + x );
|
||||
if( !num && old_rating >= x ) {
|
||||
ratingElement.src = VoteNY.imagePath + 'star_' + star_on + '.gif';
|
||||
} else {
|
||||
ratingElement.src = VoteNY.imagePath + 'star_off.gif';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
updateRating: function( id, num, prev_rating ) {
|
||||
if( VoteNY.clearRatingTimer && VoteNY.last_id == id ) {
|
||||
clearTimeout( VoteNY.clearRatingTimer );
|
||||
}
|
||||
VoteNY.clearRating( id, num, prev_rating );
|
||||
for( var x = 1; x <= num; x++ ) {
|
||||
document.getElementById( 'rating_' + id + '_' + x ).src = VoteNY.imagePath + 'star_voted.gif';
|
||||
}
|
||||
VoteNY.last_id = id;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/**
|
||||
* Vote extension - JavaScript-based voting with the <vote> tag
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
* @version 2.3.3
|
||||
* @author Aaron Wright <aaron.wright@gmail.com>
|
||||
* @author David Pean <david.pean@gmail.com>
|
||||
* @author Jack Phoenix <jack@countervandalism.net>
|
||||
* @link http://www.mediawiki.org/wiki/Extension:VoteNY Documentation
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
|
||||
*/
|
||||
|
||||
/**
|
||||
* Protect against register_globals vulnerabilities.
|
||||
* This line must be present before any global variable is referenced.
|
||||
*/
|
||||
if ( !defined( 'MEDIAWIKI' ) ) {
|
||||
die( "This is not a valid entry point.\n" );
|
||||
}
|
||||
|
||||
// Extension credits that show up on Special:Version
|
||||
$wgExtensionCredits['parserhook'][] = array(
|
||||
'name' => 'Vote',
|
||||
'version' => '2.3.3',
|
||||
'author' => array( 'Aaron Wright', 'David Pean', 'Jack Phoenix' ),
|
||||
'description' => 'JavaScript-based voting with the <tt><vote></tt> tag',
|
||||
'url' => 'http://www.mediawiki.org/wiki/Extension:VoteNY'
|
||||
);
|
||||
|
||||
// Path to Vote extension files
|
||||
$wgVoteDirectory = "$IP/extensions/VoteNY";
|
||||
|
||||
// New user right
|
||||
$wgAvailableRights[] = 'vote';
|
||||
$wgGroupPermissions['*']['vote'] = false; // Anonymous users cannot vote
|
||||
$wgGroupPermissions['user']['vote'] = true; // Registered users can vote
|
||||
|
||||
// AJAX functions needed by this extension
|
||||
require_once( 'Vote_AjaxFunctions.php' );
|
||||
|
||||
// Autoload classes and set up i18n
|
||||
$dir = dirname( __FILE__ ) . '/';
|
||||
$wgExtensionMessagesFiles['Vote'] = $dir . 'Vote.i18n.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['MakeGlobalVariablesScript'][] = 'VoteHooks::addJSGlobalVariables';
|
||||
$wgHooks['RenameUserSQL'][] = 'VoteHooks::onUserRename';
|
||||
// Translations for {{NUMBEROFVOTES}}
|
||||
//$wgExtensionMessagesFiles['NumberOfVotes'] = $dir . 'Vote.i18n.magic.php';
|
||||
$wgHooks['LanguageGetMagic'][] = 'VoteHooks::setUpMagicWord';
|
||||
$wgHooks['ParserGetVariableValueSwitch'][] = 'VoteHooks::assignValueToMagicWord';
|
||||
$wgHooks['MagicWordwgVariableIDs'][] = 'VoteHooks::registerVariableId';
|
||||
$wgHooks['LoadExtensionSchemaUpdates'][] = 'VoteHooks::addTable';
|
||||
|
||||
// ResourceLoader support for MediaWiki 1.17+
|
||||
$wgResourceModules['ext.voteNY'] = array(
|
||||
'styles' => 'Vote.css',
|
||||
'scripts' => 'Vote.js',
|
||||
'messages' => array( 'vote-link', 'vote-unvote-link' ),
|
||||
'localBasePath' => dirname( __FILE__ ),
|
||||
'remoteExtPath' => 'VoteNY',
|
||||
'position' => 'top' // available since r85616
|
||||
);
|
|
@ -0,0 +1,355 @@
|
|||
<?php
|
||||
/**
|
||||
* Vote class - class for handling vote-related functions (counting
|
||||
* the average score of a given page, inserting/updating/removing a vote etc.)
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
*/
|
||||
class Vote {
|
||||
var $PageID = 0;
|
||||
var $Userid = 0;
|
||||
var $Username = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param $pageID Integer: article ID number
|
||||
*/
|
||||
public function __construct( $pageID ) {
|
||||
global $wgUser;
|
||||
|
||||
$this->PageID = $pageID;
|
||||
$this->Username = $wgUser->getName();
|
||||
$this->Userid = $wgUser->getID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts all votes, fetching the data from memcached if available
|
||||
* or from the database if memcached isn't available
|
||||
* @return Integer: amount of votes
|
||||
*/
|
||||
function count() {
|
||||
global $wgMemc;
|
||||
$key = wfMemcKey( 'vote', 'count', $this->PageID );
|
||||
$data = $wgMemc->get( $key );
|
||||
|
||||
// Try cache
|
||||
if( $data ) {
|
||||
wfDebug( "Loading vote count for page {$this->PageID} from cache\n" );
|
||||
$vote_count = $data;
|
||||
} else {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$vote_count = 0;
|
||||
$res = $dbr->select(
|
||||
'Vote',
|
||||
'COUNT(*) AS VoteCount',
|
||||
array( 'vote_page_id' => $this->PageID ),
|
||||
__METHOD__
|
||||
);
|
||||
$row = $dbr->fetchObject( $res );
|
||||
if( $row ) {
|
||||
$vote_count = $row->VoteCount;
|
||||
}
|
||||
$wgMemc->set( $key, $vote_count );
|
||||
}
|
||||
return $vote_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the average score of all votes
|
||||
* @return Integer: formatted average number of votes (something like 3.50)
|
||||
*/
|
||||
function getAverageVote() {
|
||||
global $wgMemc;
|
||||
$key = wfMemcKey( 'vote', 'avg', $this->PageID );
|
||||
$data = $wgMemc->get( $key );
|
||||
|
||||
$voteAvg = 0;
|
||||
if( $data ) {
|
||||
wfDebug( "Loading vote avg for page {$this->PageID} from cache\n" );
|
||||
$voteAvg = $data;
|
||||
} else {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$res = $dbr->select(
|
||||
'Vote',
|
||||
'AVG(vote_value) AS VoteAvg',
|
||||
array( 'vote_page_id' => $this->PageID ),
|
||||
__METHOD__
|
||||
);
|
||||
$row = $dbr->fetchObject( $res );
|
||||
if( $row ) {
|
||||
$voteAvg = $row->VoteAvg;
|
||||
}
|
||||
$wgMemc->set( $key, $voteAvg );
|
||||
}
|
||||
return number_format( $voteAvg, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear caches - memcached, parser cache and Squid cache
|
||||
*/
|
||||
function clearCache() {
|
||||
global $wgUser, $wgMemc;
|
||||
|
||||
// Kill internal cache
|
||||
$wgMemc->delete( wfMemcKey( 'vote', 'count', $this->PageID ) );
|
||||
$wgMemc->delete( wfMemcKey( 'vote', 'avg', $this->PageID ) );
|
||||
|
||||
// Purge squid
|
||||
$page_title = Title::newFromID( $this->PageID );
|
||||
if( is_object( $page_title ) ) {
|
||||
$page_title->invalidateCache();
|
||||
$page_title->purgeSquid();
|
||||
|
||||
// Kill parser cache
|
||||
$article = new Article( $page_title );
|
||||
$parserCache =& ParserCache::singleton();
|
||||
$parser_key = $parserCache->getKey( $article, $wgUser );
|
||||
$wgMemc->delete( $parser_key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the user's vote from the DB if s/he wants to remove his/her vote
|
||||
*/
|
||||
function delete() {
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
$dbw->delete(
|
||||
'Vote',
|
||||
array(
|
||||
'vote_page_id' => $this->PageID,
|
||||
'username' => $this->Username
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
$dbw->commit();
|
||||
|
||||
$this->clearCache();
|
||||
|
||||
// Update social statistics if SocialProfile extension is enabled
|
||||
if( class_exists( 'UserStatsTrack' ) ) {
|
||||
$stats = new UserStatsTrack( $this->Userid, $this->Username );
|
||||
$stats->decStatField( 'vote' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a new vote into the Vote database table
|
||||
* @param $voteValue
|
||||
*/
|
||||
function insert( $voteValue ) {
|
||||
$dbw = wfGetDB( DB_MASTER );
|
||||
wfSuppressWarnings(); // E_STRICT whining
|
||||
$voteDate = date( 'Y-m-d H:i:s' );
|
||||
wfRestoreWarnings();
|
||||
if( $this->UserAlreadyVoted() == false ) {
|
||||
$dbw->insert(
|
||||
'Vote',
|
||||
array(
|
||||
'username' => $this->Username,
|
||||
'vote_user_id' => $this->Userid,
|
||||
'vote_page_id' => $this->PageID,
|
||||
'vote_value' => $voteValue,
|
||||
'vote_date' => $voteDate,
|
||||
'vote_ip' => wfGetIP()
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
$dbw->commit();
|
||||
|
||||
$this->clearCache();
|
||||
|
||||
// Update social statistics if SocialProfile extension is enabled
|
||||
if( class_exists( 'UserStatsTrack' ) ) {
|
||||
$stats = new UserStatsTrack( $this->Userid, $this->Username );
|
||||
$stats->incStatField( 'vote' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a user has already voted
|
||||
* @return Boolean: false if s/he hasn't, otherwise returns the value of
|
||||
* 'vote_value' column from Vote DB table
|
||||
*/
|
||||
function UserAlreadyVoted() {
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$s = $dbr->selectRow(
|
||||
'Vote',
|
||||
array( 'vote_value' ),
|
||||
array(
|
||||
'vote_page_id' => $this->PageID,
|
||||
'username' => $this->Username
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
if( $s === false ) {
|
||||
return false;
|
||||
} else {
|
||||
return $s->vote_value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the green voting box
|
||||
* @return Mixed: HTML output
|
||||
*/
|
||||
function display() {
|
||||
global $wgUser;
|
||||
|
||||
$this->votekey = md5( $this->PageID . 'pants' . $this->Username );
|
||||
$voted = $this->UserAlreadyVoted();
|
||||
|
||||
$make_vote_box_clickable = '';
|
||||
if( $voted == false ) {
|
||||
$make_vote_box_clickable = ' vote-clickable';
|
||||
}
|
||||
|
||||
$output = "<div class=\"vote-box{$make_vote_box_clickable}\" id=\"votebox\" onclick=\"VoteNY.clickVote(1,{$this->PageID},'{$this->votekey}')\">";
|
||||
$output .= '<span id="PollVotes" class="vote-number">' . $this->count() . '</span>';
|
||||
$output .= '</div>';
|
||||
$output .= '<div id="Answer" class="vote-action">';
|
||||
|
||||
if ( !$wgUser->isAllowed( 'vote' ) ) {
|
||||
// @todo FIXME: this is horrible. If we don't have enough
|
||||
// permissions to vote, we should tell the end-user /that/,
|
||||
// not require them to log in!
|
||||
$login = SpecialPage::getTitleFor( 'Userlogin' );
|
||||
$output .= '<a class="votebutton" href="' .
|
||||
$login->escapeFullURL() . '" rel="nofollow">' .
|
||||
wfMsg( 'vote-link' ) . '</a>';
|
||||
} else {
|
||||
if( !wfReadOnly() ) {
|
||||
if( $voted == false ) {
|
||||
$output .= "<a href=\"javascript:VoteNY.clickVote(1,{$this->PageID},'{$this->votekey}')\">" .
|
||||
wfMsg( 'vote-link' ) . '</a>';
|
||||
} else {
|
||||
$output .= "<a href=\"javascript:VoteNY.unVote('{$this->PageID}', '{$this->votekey}')\">" .
|
||||
wfMsg( 'vote-unvote-link' ) . '</a>';
|
||||
}
|
||||
}
|
||||
}
|
||||
$output .= '</div>';
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for generating star rating stars.
|
||||
*/
|
||||
class VoteStars extends Vote {
|
||||
|
||||
var $maxRating = 5;
|
||||
|
||||
/**
|
||||
* Displays voting stars
|
||||
* @param $voted Boolean: false by default
|
||||
* @return Mixed: HTML output
|
||||
*/
|
||||
function display( $voted = false ) {
|
||||
global $wgUser;
|
||||
|
||||
$overall_rating = $this->getAverageVote();
|
||||
|
||||
if( $voted ) {
|
||||
$display_stars_rating = $voted;
|
||||
} else {
|
||||
$display_stars_rating = $this->getAverageVote();
|
||||
}
|
||||
|
||||
$this->votekey = md5( $this->PageID . 'pants' . $this->Username );
|
||||
$id = '';
|
||||
|
||||
// Should probably be $this->PageID or something?
|
||||
// 'cause we define $id just above as an empty string...duh
|
||||
$output = '<div id="rating_' . $id . '">';
|
||||
$output .= '<div class="rating-score">';
|
||||
$output .= '<div class="voteboxrate">' . $overall_rating . '</div>';
|
||||
$output .= '</div>';
|
||||
$output .= '<div class="rating-section">';
|
||||
$output .= $this->displayStars( $id, $display_stars_rating, $voted );
|
||||
$count = $this->count();
|
||||
if( $count ) {
|
||||
$output .= ' <span class="rating-total">(' .
|
||||
wfMsgExt( 'vote-votes', 'parsemag', $count ) . ')</span>';
|
||||
}
|
||||
$already_voted = $this->UserAlreadyVoted();
|
||||
if( $already_voted && $wgUser->isLoggedIn() ) {
|
||||
$output .= '<div class="rating-voted">' .
|
||||
wfMsgExt( 'vote-gave-this', 'parsemag', $already_voted ) .
|
||||
" </div>
|
||||
<a href=\"javascript:VoteNY.unVoteStars({$this->PageID},'{$this->votekey}','{$id}')\">("
|
||||
. wfMsg( 'vote-remove' ) .
|
||||
')</a>';
|
||||
}
|
||||
$output .= '</div>
|
||||
<div class="rating-clear">
|
||||
</div>';
|
||||
|
||||
$output .= '</div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the actual star images, depending on the state of the user's mouse
|
||||
* @param $id Integer: ID of the rating (div) element
|
||||
* @param $rating Integer: average rating
|
||||
* @param $voted Integer
|
||||
* @return Mixed: generated <img> tag
|
||||
*/
|
||||
function displayStars( $id, $rating, $voted ) {
|
||||
global $wgScriptPath;
|
||||
|
||||
if( !$rating ) {
|
||||
$rating = 0;
|
||||
}
|
||||
$this->votekey = md5( $this->PageID . 'pants' . $this->Username );
|
||||
if( !$voted ) {
|
||||
$voted = 0;
|
||||
}
|
||||
$output = '';
|
||||
|
||||
for( $x = 1; $x <= $this->maxRating; $x++ ) {
|
||||
if( !$id ) {
|
||||
$action = 3;
|
||||
} else {
|
||||
$action = 5;
|
||||
}
|
||||
$onclick = "VoteNY.clickVoteStars({$x},{$this->PageID},'{$this->votekey}','{$id}',$action);";
|
||||
$onmouseover = "VoteNY.updateRating('{$id}',{$x},{$rating});";
|
||||
$onmouseout = "VoteNY.startClearRating('{$id}','{$rating}',{$voted});";
|
||||
$output .= "<img onclick=\"javascript:{$onclick}\" onmouseover=\"javascript:{$onmouseover}\" onmouseout=\"javascript:{$onmouseout}\" id=\"rating_{$id}_{$x}\" src=\"{$wgScriptPath}/extensions/VoteNY/images/star_";
|
||||
switch( true ) {
|
||||
case $rating >= $x:
|
||||
if( $voted ) {
|
||||
$output .= 'voted';
|
||||
} else {
|
||||
$output .= 'on';
|
||||
}
|
||||
break;
|
||||
case( $rating > 0 && $rating < $x && $rating > ( $x - 1 ) ):
|
||||
$output .= 'half';
|
||||
break;
|
||||
case( $rating < $x ):
|
||||
$output .= 'off';
|
||||
break;
|
||||
}
|
||||
|
||||
$output .= '.gif" alt="" />';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the average score for the current page
|
||||
* and the total amount of votes.
|
||||
*/
|
||||
function displayScore() {
|
||||
$count = $this->count();
|
||||
return wfMsg( 'vote-community-score', '<b>' . $this->getAverageVote() . '</b>' ) .
|
||||
' (' . wfMsgExt( 'vote-ratings', 'parsemag', $count ) . ')';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
<?php
|
||||
/**
|
||||
* All hooked functions used by VoteNY extension.
|
||||
*
|
||||
* @file
|
||||
* @ingroup Extensions
|
||||
*/
|
||||
class VoteHooks {
|
||||
|
||||
/**
|
||||
* Set up the <vote> parser hook.
|
||||
*
|
||||
* @param $parser Parser: instance of Parser
|
||||
* @return Boolean: true
|
||||
*/
|
||||
public static function registerParserHook( &$parser ) {
|
||||
$parser->setHook( 'vote', array( 'VoteHooks', 'renderVote' ) );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for registerParserHook.
|
||||
*
|
||||
* @param $input String: user-supplied input, unused
|
||||
* @param $args Array: user-supplied arguments, unused
|
||||
* @param $parser Parser: instance of Parser, unused
|
||||
* @return String: HTML
|
||||
*/
|
||||
public static function renderVote( $input, $args, $parser ) {
|
||||
global $wgOut, $wgTitle, $wgScriptPath;
|
||||
|
||||
wfProfileIn( __METHOD__ );
|
||||
|
||||
// Disable parser cache (sadly we have to do this, because the caching is
|
||||
// messing stuff up; we want to show an up-to-date rating instead of old
|
||||
// or totally wrong rating, i.e. another page's rating...)
|
||||
$parser->disableCache();
|
||||
|
||||
// Add CSS & JS
|
||||
// In order for us to do this *here* instead of having to do this in
|
||||
// registerParserHook(), we must've disabled parser cache
|
||||
if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
|
||||
$wgOut->addModules( 'ext.voteNY' );
|
||||
} else {
|
||||
$wgOut->addScriptFile( $wgScriptPath . '/extensions/VoteNY/Vote.js' );
|
||||
$wgOut->addExtensionStyle( $wgScriptPath . '/extensions/VoteNY/Vote.css' );
|
||||
}
|
||||
|
||||
// Define variable - 0 means that we'll get that green voting box by default
|
||||
$type = 0;
|
||||
|
||||
// Determine what kind of a voting gadget the user wants: a box or pretty stars?
|
||||
if( preg_match( "/^\s*type\s*=\s*(.*)/mi", $input, $matches ) ) {
|
||||
$type = htmlspecialchars( $matches[1] );
|
||||
} elseif( !empty( $args['type'] ) ) {
|
||||
$type = intval( $args['type'] );
|
||||
}
|
||||
|
||||
$articleID = $wgTitle->getArticleID();
|
||||
switch( $type ) {
|
||||
case 0:
|
||||
$vote = new Vote( $articleID );
|
||||
break;
|
||||
case 1:
|
||||
$vote = new VoteStars( $articleID );
|
||||
break;
|
||||
default:
|
||||
$vote = new Vote( $articleID );
|
||||
}
|
||||
|
||||
$output = $vote->display();
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds required JS variables to the HTML output.
|
||||
*
|
||||
* @param $vars Array: array of pre-existing JS globals
|
||||
* @return Boolean: true
|
||||
*/
|
||||
public static function addJSGlobalVariables( $vars ) {
|
||||
$vars['_VOTE_LINK'] = wfMsg( 'vote-link' );
|
||||
$vars['_UNVOTE_LINK'] = wfMsg( 'vote-unvote-link' );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the Renameuser extension.
|
||||
*
|
||||
* @param $renameUserSQL
|
||||
* @return Boolean: true
|
||||
*/
|
||||
public static function onUserRename( $renameUserSQL ) {
|
||||
$renameUserSQL->tables['Vote'] = array( 'username', 'vote_user_id' );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the {{NUMBEROFVOTES}} magic word.
|
||||
*
|
||||
* @param $magicWords Array: array of magic words
|
||||
* @param $langID
|
||||
* @return Boolean: true
|
||||
*/
|
||||
public static function setUpMagicWord( &$magicWords, $langID ) {
|
||||
// tell MediaWiki that {{NUMBEROFVOTES}} and all case variants found in
|
||||
// wiki text should be mapped to magic ID 'NUMBEROFVOTES'
|
||||
// (0 means case-insensitive)
|
||||
$magicWords['NUMBEROFVOTES'] = array( 0, 'NUMBEROFVOTES' );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a value to {{NUMBEROFVOTES}}. First we try memcached and if that
|
||||
* fails, we fetch it directly from the database and cache it for 24 hours.
|
||||
*
|
||||
* @param $parser Parser
|
||||
* @param $cache
|
||||
* @param $magicWordId String: magic word ID
|
||||
* @param $ret Integer: return value (number of votes)
|
||||
* @return Boolean: true
|
||||
*/
|
||||
public static function assignValueToMagicWord( &$parser, &$cache, &$magicWordId, &$ret ) {
|
||||
global $wgMemc;
|
||||
|
||||
if ( $magicWordId == 'NUMBEROFVOTES' ) {
|
||||
$key = wfMemcKey( 'vote', 'magic-word' );
|
||||
$data = $wgMemc->get( $key );
|
||||
if ( $data != '' ) {
|
||||
// We have it in cache? Oh goody, let's just use the cached value!
|
||||
wfDebugLog(
|
||||
'VoteNY',
|
||||
'Got the amount of votes from memcached'
|
||||
);
|
||||
// return value
|
||||
$ret = $data;
|
||||
} else {
|
||||
// Not cached → have to fetch it from the database
|
||||
$dbr = wfGetDB( DB_SLAVE );
|
||||
$voteCount = (int)$dbr->selectField(
|
||||
'Vote',
|
||||
'COUNT(*) AS count',
|
||||
array(),
|
||||
__METHOD__
|
||||
);
|
||||
wfDebugLog( 'VoteNY', 'Got the amount of votes from DB' );
|
||||
// Store the count in cache...
|
||||
// (86400 = seconds in a day)
|
||||
$wgMemc->set( $key, $voteCount, 86400 );
|
||||
// ...and return the value to the user
|
||||
$ret = $voteCount;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the magic word ID for {{NUMBEROFVOTES}}.
|
||||
*
|
||||
* @param $variableIds Array: array of pre-existing variable IDs
|
||||
* @return Boolean: true
|
||||
*/
|
||||
public static function registerVariableId( &$variableIds ) {
|
||||
$variableIds[] = 'NUMBEROFVOTES';
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the necessary database table when the user runs
|
||||
* maintenance/update.php.
|
||||
*
|
||||
* @param $updater Object: instance of DatabaseUpdater
|
||||
* @return Boolean: true
|
||||
*/
|
||||
public static function addTable( $updater = null ) {
|
||||
$dir = dirname( __FILE__ );
|
||||
$file = "$dir/vote.sql";
|
||||
if ( $updater === null ) {
|
||||
global $wgExtNewTables;
|
||||
$wgExtNewTables[] = array( 'Vote', $file );
|
||||
} else {
|
||||
$updater->addExtensionUpdate( array( 'addTable', 'Vote', $file, true ) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
/**
|
||||
* AJAX functions used by Vote extension.
|
||||
*/
|
||||
$wgAjaxExportList[] = 'wfVoteClick';
|
||||
|
||||
function wfVoteClick( $voteValue, $pageId, $mk ) {
|
||||
global $wgUser;
|
||||
|
||||
if ( !$wgUser->isAllowed( 'vote' ) ) {
|
||||
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, $mk ) {
|
||||
global $wgUser;
|
||||
|
||||
if ( !$wgUser->isAllowed( 'vote' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if( is_numeric( $pageId ) ) {
|
||||
$vote = new Vote( $pageId );
|
||||
$vote->delete();
|
||||
|
||||
return $vote->count( 1 );
|
||||
} else {
|
||||
return 'error';
|
||||
}
|
||||
}
|
||||
|
||||
$wgAjaxExportList[] = 'wfVoteStars';
|
||||
function wfVoteStars( $voteValue, $pageId, $mk ) {
|
||||
global $wgUser;
|
||||
|
||||
if ( !$wgUser->isAllowed( 'vote' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$vote = new VoteStars( $pageId );
|
||||
if( $vote->UserAlreadyVoted() ) {
|
||||
$vote->delete();
|
||||
}
|
||||
$vote->insert( $voteValue );
|
||||
|
||||
return $vote->display( $voteValue );
|
||||
}
|
||||
|
||||
$wgAjaxExportList[] = 'wfVoteStarsMulti';
|
||||
function wfVoteStarsMulti( $voteValue, $pageId, $mk ) {
|
||||
global $wgUser;
|
||||
|
||||
if ( !$wgUser->isAllowed( 'vote' ) ) {
|
||||
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( 'vote' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$vote = new VoteStars( $pageId );
|
||||
$vote->delete();
|
||||
|
||||
return $vote->display();
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 637 B |
Binary file not shown.
After Width: | Height: | Size: 631 B |
Binary file not shown.
After Width: | Height: | Size: 627 B |
Binary file not shown.
After Width: | Height: | Size: 612 B |
|
@ -0,0 +1,21 @@
|
|||
CREATE TABLE /*_*/Vote (
|
||||
-- Internal ID to identify between different vote tags on different pages
|
||||
`vote_id` int(11) NOT NULL auto_increment PRIMARY KEY,
|
||||
-- Username (if any) of the person who voted
|
||||
`username` varchar(255) NOT NULL default '0',
|
||||
-- User ID of the person who voted
|
||||
`vote_user_id` int(11) NOT NULL default '0',
|
||||
-- ID of the page where the vote tag is in
|
||||
`vote_page_id` int(11) NOT NULL default '0',
|
||||
-- Value of the vote (ranging from 1 to 5)
|
||||
`vote_value` char(1) character set latin1 collate latin1_bin NOT NULL default '',
|
||||
-- Timestamp when the vote was cast
|
||||
`vote_date` datetime NOT NULL default '0000-00-00 00:00:00',
|
||||
-- IP address of the user who voted
|
||||
`vote_ip` varchar(45) NOT NULL default ''
|
||||
) /*$wgDBTableOptions*/;
|
||||
|
||||
CREATE INDEX vote_page_id_index ON /*_*/Vote (vote_page_id);
|
||||
CREATE INDEX valueidx ON /*_*/Vote (vote_value);
|
||||
CREATE INDEX usernameidx ON /*_*/Vote (username);
|
||||
CREATE INDEX vote_date ON /*_*/Vote (vote_date);
|
Loading…
Reference in New Issue