Actor support, now requires MW 1.34(+)

Bug: T227345
Change-Id: I6b3cefb37efe770f7dcb7f7c093bf71e1e8bb543
This commit is contained in:
Jack Phoenix 2020-01-08 20:43:41 +02:00
parent 0332e5649c
commit 125e943aa2
9 changed files with 130 additions and 40 deletions

View file

@ -1,6 +1,6 @@
{
"name": "AJAX Poll",
"version": "2.1",
"version": "2.2",
"author": [
"Dariusz Siedlecki",
"Jack Phoenix",
@ -11,7 +11,7 @@
"type": "parserhook",
"license-name": "GFDL-1.2",
"requires": {
"MediaWiki": ">= 1.30.0"
"MediaWiki": ">= 1.34.0"
},
"GroupPermissions": {
"*": {
@ -39,7 +39,8 @@
},
"AutoloadClasses": {
"AJAXPoll": "includes/AJAXPoll.class.php",
"ApiAJAXPollSubmitVote": "includes/api/ApiAJAXPollSubmitVote.php"
"ApiAJAXPollSubmitVote": "includes/api/ApiAJAXPollSubmitVote.php",
"MigrateOldAJAXPollUserColumnsToActor": "maintenance/migrateOldAJAXPollUserColumnsToActor.php"
},
"ResourceModules": {
"ext.ajaxpoll": {

View file

@ -34,18 +34,12 @@ class AJAXPoll {
* @return string
*/
public static function render( $input, $args = [], Parser $parser, $frame ) {
global $wgUser, $wgRequest;
global $wgUser;
$parser->getOutput()->updateCacheExpiry( 0 );
$parser->addTrackingCategory( 'ajaxpoll-tracking-category' );
$parser->getOutput()->addModules( 'ext.ajaxpoll' );
if ( $wgUser->getName() == '' ) {
$userName = $wgRequest->getIP();
} else {
$userName = $wgUser->getName();
}
// ID of the poll
if ( isset( $args['id'] ) ) {
$id = $args['id'];
@ -125,7 +119,7 @@ class AJAXPoll {
[
'id' => 'ajaxpoll-container-' . $id
],
self::buildHTML( $id, $userName, $lines )
self::buildHTML( $id, $wgUser, $lines )
);
break;
}
@ -141,7 +135,7 @@ class AJAXPoll {
[
'COUNT(*)',
'COUNT(DISTINCT poll_id)',
'COUNT(DISTINCT poll_user)',
'COUNT(DISTINCT poll_actor)',
'TIMEDIFF(NOW(), MAX(poll_date))'
],
[],
@ -183,17 +177,12 @@ During the last 48 hours, $tab2[0] votes have been given.";
}
public static function submitVote( $id, $answer ) {
global $wgUser, $wgRequest;
if ( $wgUser->getName() == '' ) {
$userName = $wgRequest->getIP();
} else {
$userName = $wgUser->getName();
}
global $wgUser;
if ( !$wgUser->isAllowed( 'ajaxpoll-vote' ) || $wgUser->isBot() ) {
return self::buildHTML( $id, $userName );
return self::buildHTML( $id, $wgUser );
}
$user = $wgUser;
$dbw = wfGetDB( DB_MASTER );
$dbw->startAtomic( __METHOD__ );
@ -206,24 +195,24 @@ During the last 48 hours, $tab2[0] votes have been given.";
'COUNT(*) AS count',
[
'poll_id' => $id,
'poll_user' => $userName
'poll_actor' => $user->getActorId()
],
__METHOD__
);
$row = $dbw->fetchRow( $q );
if ( $row['count'] > 0 ) {
$pollContainerText = self::updateVote( $dbw, $id, $userName, $answer );
$pollContainerText = self::updateVote( $dbw, $id, $user, $answer );
} else {
$pollContainerText = self::addVote( $dbw, $id, $userName, $answer );
$pollContainerText = self::addVote( $dbw, $id, $user, $answer );
}
} else { // revoking a vote
$pollContainerText = self::revokeVote( $dbw, $id, $userName );
$pollContainerText = self::revokeVote( $dbw, $id, $user );
}
$dbw->endAtomic( __METHOD__ );
return self::buildHTML( $id, $userName, '', $pollContainerText );
return self::buildHTML( $id, $user, '', $pollContainerText );
}
/**
@ -236,17 +225,17 @@ During the last 48 hours, $tab2[0] votes have been given.";
*
* @param IDatabase $dbw Write connection to a database
* @param string $id Poll ID
* @param string $userName User name or IP address of the person voting
* @param User $user User (object) who is voting
* @param int $answer Answer option #
* @return string Name of an i18n msg to show to the user
*/
public static function addVote( $dbw, $id, $userName, $answer ) {
public static function addVote( $dbw, $id, $user, $answer ) {
global $wgRequest;
$insertQuery = $dbw->insert(
'ajaxpoll_vote',
[
'poll_id' => $id,
'poll_user' => $userName,
'poll_actor' => $user->getActorId(),
'poll_ip' => $wgRequest->getIP(),
'poll_answer' => $answer,
'poll_date' => wfTimestampNow()
@ -259,15 +248,15 @@ During the last 48 hours, $tab2[0] votes have been given.";
/**
* @param IDatabase $dbw Write connection to a database
* @param string $id Poll ID
* @param string $userName User name or IP address of the person voting
* @param User $user User (object) who is voting
* @return string Name of an i18n msg to show to the user
*/
public static function revokeVote( $dbw, $id, $userName ) {
public static function revokeVote( $dbw, $id, $user ) {
$deleteQuery = $dbw->delete(
'ajaxpoll_vote',
[
'poll_id' => $id,
'poll_user' => $userName,
'poll_actor' => $user->getActorId()
],
__METHOD__
);
@ -277,11 +266,11 @@ During the last 48 hours, $tab2[0] votes have been given.";
/**
* @param IDatabase $dbw Write connection to a database
* @param string $id Poll ID
* @param string $userName User name or IP address of the person voting
* @param User $user User (object) who is voting
* @param int $answer Answer option #
* @return string Name of an i18n msg to show to the user
*/
public static function updateVote( $dbw, $id, $userName, $answer ) {
public static function updateVote( $dbw, $id, $user, $answer ) {
$updateQuery = $dbw->update(
'ajaxpoll_vote',
[
@ -290,7 +279,7 @@ During the last 48 hours, $tab2[0] votes have been given.";
],
[
'poll_id' => $id,
'poll_user' => $userName,
'poll_actor' => $user->getActorId()
],
__METHOD__
);
@ -301,7 +290,7 @@ During the last 48 hours, $tab2[0] votes have been given.";
return htmlspecialchars( Sanitizer::decodeCharReferences( $string ), ENT_QUOTES );
}
private static function buildHTML( $id, $userName, $lines = '', $extra_from_ajax = '' ) {
private static function buildHTML( $id, $user, $lines = '', $extra_from_ajax = '' ) {
global $wgTitle, $wgUser, $wgLang;
$dbr = wfGetDB( DB_REPLICA );
@ -350,7 +339,7 @@ During the last 48 hours, $tab2[0] votes have been given.";
[ 'poll_answer', 'poll_date' ],
[
'poll_id' => $id,
'poll_user' => $userName
'poll_actor' => $user->getActorId()
],
__METHOD__
);
@ -646,5 +635,30 @@ During the last 48 hours, $tab2[0] votes have been given.";
$patchPath . 'create-table--ajaxpoll_vote.sql'
);
}
// Actor support
// 1) add new actor column
// @codingStandardsIgnoreLine
$updater->addExtensionField( 'ajaxpoll_vote', 'poll_actor', $patchPath . 'add-field-ajaxpoll_vote-poll_actor.sql' );
// 2) do magic
// This includes, but is not limited to, changing the PRIMARY KEY,
// adding a new, UNIQUE INDEX on a new AUTO_INCREMENT field (which the
// script also creates) and, of course, finally the new column is populated
// with data.
// PITFALL WARNING! Do NOT change this to $updater->runMaintenance,
// THEY ARE NOT THE SAME THING and this MUST be using addExtensionUpdate
// instead for the code to work as desired!
// HT Skizzerz
$updater->addExtensionUpdate( [
'runMaintenance',
'MigrateOldAJAXPollUserColumnsToActor',
'../maintenance/migrateOldAJAXPollUserColumnsToActor.php'
] );
// 3) drop the now unused column
// @codingStandardsIgnoreLine
$updater->dropExtensionField( 'ajaxpoll_vote', 'poll_user', $patchPath . 'drop-field-poll_user-ajaxpoll_vote.sql' );
}
}

View file

@ -0,0 +1,68 @@
<?php
/**
* @file
* @ingroup Maintenance
*/
$IP = getenv( 'MW_INSTALL_PATH' );
if ( $IP === false ) {
$IP = __DIR__ . '/../../..';
}
require_once "$IP/maintenance/Maintenance.php";
/**
* Run automatically with update.php
*
* @since January 2020
*/
class MigrateOldAJAXPollUserColumnsToActor extends LoggedUpdateMaintenance {
public function __construct() {
parent::__construct();
// @codingStandardsIgnoreLine
$this->addDescription( 'Migrates data from old poll_user column in the ajaxpoll_vote table to the new actor column.' );
}
/**
* Get the update key name to go in the update log table
*
* @return string
*/
protected function getUpdateKey() {
return __CLASS__;
}
/**
* Message to show that the update was done already and was just skipped
*
* @return string
*/
protected function updateSkippedMessage() {
return 'ajaxpoll_vote has already been migrated to use the actor column.';
}
/**
* Do the actual work.
*
* @return bool True to log the update as done
*/
protected function doDBUpdates() {
$dbw = $this->getDB( DB_MASTER );
if ( $dbw->fieldExists( 'ajaxpoll_vote', 'poll_vote_id', __METHOD__ ) ) {
return true;
}
$dbw->sourceFile( __DIR__ . '/../sql/drop-primary-key.sql' );
$dbw->sourceFile( __DIR__ . '/../sql/add-new-primary-key.sql' );
$dbw->sourceFile( __DIR__ . '/../sql/create-unique-index-poll_id_actor.sql' );
$dbw->query(
// @codingStandardsIgnoreLine
"UPDATE {$dbw->tableName( 'ajaxpoll_vote' )} SET poll_actor=(SELECT actor_id FROM {$dbw->tableName( 'actor' )} WHERE actor_name=poll_user AND actor_user IS NOT NULL)",
__METHOD__
);
return true;
}
}
$maintClass = MigrateOldAJAXPollUserColumnsToActor::class;
require_once RUN_MAINTENANCE_IF_MAIN;

View file

@ -0,0 +1 @@
ALTER TABLE /*_*/ajaxpoll_vote ADD COLUMN poll_actor bigint unsigned NOT NULL AFTER poll_id;

View file

@ -0,0 +1 @@
ALTER TABLE /*_*/ajaxpoll_vote ADD COLUMN poll_vote_id int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT FIRST;

View file

@ -1,8 +1,10 @@
CREATE TABLE IF NOT EXISTS /*_*/ajaxpoll_vote (
`poll_vote_id` int unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
`poll_id` varchar(32) NOT NULL default '',
`poll_user` varchar(255) NOT NULL default '',
`poll_actor` bigint unsigned NOT NULL,
`poll_ip` varchar(255) default NULL,
`poll_answer` int(3) default NULL,
`poll_date` datetime default NULL,
PRIMARY KEY (`poll_id`,`poll_user`)
) /*$wgDBTableOptions*/;
`poll_date` datetime default NULL
) /*$wgDBTableOptions*/;
CREATE UNIQUE INDEX /*i*/poll_id_actor ON /*_*/ajaxpoll_vote (poll_id, poll_actor);

View file

@ -0,0 +1 @@
CREATE UNIQUE INDEX /*i*/poll_id_actor ON /*_*/ajaxpoll_vote (poll_id, poll_actor);

View file

@ -0,0 +1 @@
ALTER TABLE /*_*/ajaxpoll_vote DROP COLUMN poll_user;

1
sql/drop-primary-key.sql Normal file
View file

@ -0,0 +1 @@
ALTER TABLE /*_*/ajaxpoll_vote DROP PRIMARY KEY;