2012-02-19 19:31:24 +00:00
|
|
|
<?php
|
2015-09-29 20:40:24 +00:00
|
|
|
|
2020-01-28 22:28:04 +00:00
|
|
|
use MediaWiki\MediaWikiServices;
|
|
|
|
|
2012-02-19 19:31:24 +00:00
|
|
|
/**
|
|
|
|
* AJAX Poll class
|
|
|
|
* Created by Dariusz Siedlecki, based on the work by Eric David.
|
|
|
|
* Licensed under the GFDL.
|
|
|
|
*
|
|
|
|
* @file
|
|
|
|
* @ingroup Extensions
|
|
|
|
* @author Dariusz Siedlecki <datrio@gmail.com>
|
2017-11-11 21:51:27 +00:00
|
|
|
* @author Jack Phoenix
|
2012-02-19 19:31:24 +00:00
|
|
|
* @author Thomas Gries
|
|
|
|
* @maintainer Thomas Gries
|
2018-05-12 12:27:22 +00:00
|
|
|
* @link https://www.mediawiki.org/wiki/Extension:AJAX_Poll Documentation
|
2012-02-19 19:31:24 +00:00
|
|
|
*/
|
|
|
|
class AJAXPoll {
|
|
|
|
|
|
|
|
/**
|
2015-09-29 20:40:24 +00:00
|
|
|
* Register <poll> tag with the parser
|
|
|
|
*
|
2018-01-11 19:24:38 +00:00
|
|
|
* @param Parser $parser A parser instance, not necessarily $wgParser
|
2015-09-29 20:40:24 +00:00
|
|
|
*/
|
2018-05-12 12:27:22 +00:00
|
|
|
public static function onParserFirstCallInit( $parser ) {
|
|
|
|
$parser->setHook( 'poll', [ __CLASS__, 'render' ] );
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2018-01-11 19:24:38 +00:00
|
|
|
/**
|
|
|
|
* The callback function for converting the input text to HTML output
|
2018-05-12 12:27:22 +00:00
|
|
|
*
|
2018-01-11 19:24:38 +00:00
|
|
|
* @param string $input
|
|
|
|
* @param array $args
|
|
|
|
* @param Parser $parser
|
|
|
|
* @param PPFrame $frame
|
|
|
|
* @return string
|
|
|
|
*/
|
2022-10-09 00:44:18 +00:00
|
|
|
public static function render( $input, $args, Parser $parser, $frame ) {
|
2018-01-06 18:40:14 +00:00
|
|
|
$parser->getOutput()->updateCacheExpiry( 0 );
|
2012-03-19 18:45:57 +00:00
|
|
|
$parser->addTrackingCategory( 'ajaxpoll-tracking-category' );
|
2022-02-12 01:10:21 +00:00
|
|
|
$parser->getOutput()->addModules( [ 'ext.ajaxpoll' ] );
|
2012-03-09 19:23:28 +00:00
|
|
|
|
2012-02-19 19:31:24 +00:00
|
|
|
// ID of the poll
|
2018-05-12 12:27:22 +00:00
|
|
|
if ( isset( $args['id'] ) ) {
|
|
|
|
$id = $args['id'];
|
2013-07-28 17:36:28 +00:00
|
|
|
} else {
|
|
|
|
$id = strtoupper( md5( $input ) );
|
|
|
|
}
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2013-07-28 17:36:28 +00:00
|
|
|
// get the input
|
|
|
|
$input = $parser->recursiveTagParse( $input, $frame );
|
|
|
|
$input = trim( strip_tags( $input ) );
|
2012-02-19 19:31:24 +00:00
|
|
|
$lines = explode( "\n", trim( $input ) );
|
|
|
|
|
2021-09-18 12:40:40 +00:00
|
|
|
$dbw = wfGetDB( DB_PRIMARY );
|
2012-03-12 22:13:51 +00:00
|
|
|
|
2012-02-19 19:31:24 +00:00
|
|
|
/**
|
2015-09-29 20:40:24 +00:00
|
|
|
* Register poll in the database
|
|
|
|
*/
|
2012-03-12 22:13:51 +00:00
|
|
|
|
2012-02-19 19:31:24 +00:00
|
|
|
$row = $dbw->selectRow(
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'ajaxpoll_info' ],
|
2023-04-23 02:36:59 +00:00
|
|
|
[ 'poll_show_results_before_voting' ],
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'poll_id' => $id ],
|
2012-02-19 19:31:24 +00:00
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
|
2013-05-26 10:03:15 +00:00
|
|
|
$showResultsBeforeVoting = null;
|
|
|
|
if ( array_key_exists( 'show-results-before-voting', $args ) ) {
|
|
|
|
if ( strval( $args['show-results-before-voting'] ) !== '0' ) {
|
|
|
|
$showResultsBeforeVoting = '1';
|
|
|
|
} else {
|
|
|
|
$showResultsBeforeVoting = '0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-28 22:28:04 +00:00
|
|
|
$readonly = MediaWikiServices::getInstance()->getReadOnlyMode()->getReason();
|
|
|
|
if ( !$readonly ) {
|
2023-04-23 02:36:59 +00:00
|
|
|
if ( $row === false ) {
|
2020-01-28 22:28:04 +00:00
|
|
|
$dbw->insert(
|
|
|
|
'ajaxpoll_info',
|
|
|
|
[
|
|
|
|
'poll_id' => $id,
|
|
|
|
'poll_show_results_before_voting' => $showResultsBeforeVoting,
|
|
|
|
'poll_txt' => $input,
|
2020-02-05 13:43:55 +00:00
|
|
|
'poll_date' => $dbw->timestamp( wfTimestampNow() ),
|
2020-01-28 22:28:04 +00:00
|
|
|
],
|
|
|
|
__METHOD__,
|
|
|
|
// @todo FIXME: This is a crappy hack to fix obviously incorrect and nonsensical
|
|
|
|
// "Error: 1062 Duplicate entry '<whatever>' for key 'PRIMARY' (localhost)"
|
|
|
|
// error messages, one of which I saw when literally making the very first poll
|
|
|
|
// on a wiki, so it goes w/o saying that there can't (or at least shouldn't) be
|
|
|
|
// any other entries in AJAXPoll's DB tables at that time.
|
|
|
|
// All the DB queries in this method should be refactored and ideally instead
|
|
|
|
// of insert()/update() this'd use upsert().
|
|
|
|
// @see https://phabricator.wikimedia.org/T163625
|
|
|
|
[ 'IGNORE' ]
|
|
|
|
);
|
2023-04-23 02:36:59 +00:00
|
|
|
} elseif ( $row->poll_show_results_before_voting !== $showResultsBeforeVoting ) {
|
2020-01-28 22:28:04 +00:00
|
|
|
$dbw->update(
|
|
|
|
'ajaxpoll_info',
|
|
|
|
[
|
|
|
|
'poll_show_results_before_voting' => $showResultsBeforeVoting,
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'poll_id' => $id,
|
|
|
|
],
|
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
}
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
2013-05-26 10:03:15 +00:00
|
|
|
|
2015-09-29 20:40:24 +00:00
|
|
|
switch ( $lines[0] ) {
|
2012-02-19 19:31:24 +00:00
|
|
|
case 'STATS':
|
2020-01-02 04:31:13 +00:00
|
|
|
$ret = self::buildStats();
|
2012-02-19 19:31:24 +00:00
|
|
|
break;
|
|
|
|
default:
|
2021-12-09 11:54:09 +00:00
|
|
|
if ( method_exists( $parser, 'getUserIdentity' ) ) {
|
|
|
|
// MW 1.36+
|
|
|
|
$user = MediaWikiServices::getInstance()
|
|
|
|
->getUserFactory()->newFromUserIdentity( $parser->getUserIdentity() );
|
|
|
|
} else {
|
|
|
|
$user = $parser->getUser();
|
|
|
|
}
|
2013-06-04 20:01:09 +00:00
|
|
|
$ret = Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'id' => 'ajaxpoll-container-' . $id
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2021-12-09 11:54:09 +00:00
|
|
|
self::buildHTML( $id, $user, $readonly, $lines )
|
2013-06-04 20:01:09 +00:00
|
|
|
);
|
2012-02-19 19:31:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-09-29 20:40:24 +00:00
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
return $ret;
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-02 04:31:13 +00:00
|
|
|
private static function buildStats() {
|
2017-09-01 23:39:28 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
$tab = $dbr->selectRow(
|
2012-03-14 20:28:16 +00:00
|
|
|
'ajaxpoll_vote',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2022-02-05 19:56:47 +00:00
|
|
|
'votes' => 'COUNT(*)',
|
|
|
|
'polls' => 'COUNT(DISTINCT poll_id)',
|
|
|
|
'actors' => 'COUNT(DISTINCT poll_actor)',
|
|
|
|
'timediff' => 'TIMEDIFF(NOW(), MAX(poll_date))'
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
|
|
|
[],
|
2012-02-19 19:31:24 +00:00
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
$clock = explode( ':', $tab->timediff );
|
2012-02-19 19:31:24 +00:00
|
|
|
|
|
|
|
if ( $clock[0] == '00' && $clock[1] == '00' ) {
|
|
|
|
$x = $clock[2];
|
|
|
|
$y = 'second';
|
2015-09-29 20:40:24 +00:00
|
|
|
} elseif ( $clock[0] == '00' ) {
|
2012-02-19 19:31:24 +00:00
|
|
|
$x = $clock[1];
|
|
|
|
$y = 'minute';
|
|
|
|
} else {
|
|
|
|
if ( $clock[0] < 24 ) {
|
|
|
|
$x = $clock[0];
|
|
|
|
$y = 'hour';
|
|
|
|
} else {
|
|
|
|
$x = floor( $hr / 24 );
|
|
|
|
$y = 'day';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$clockago = $x . ' ' . $y . ( $x > 1 ? 's' : '' );
|
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
$tab2 = $dbr->selectRow(
|
2012-03-14 20:28:16 +00:00
|
|
|
'ajaxpoll_vote',
|
2022-02-05 19:56:47 +00:00
|
|
|
[ 'votes' => 'COUNT(*)' ],
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'DATE_SUB(CURDATE(), INTERVAL 2 DAY) <= poll_date' ],
|
2012-02-19 19:31:24 +00:00
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
return "There are {$tab->polls} polls and {$tab->votes} votes given by {$tab->actors} different people.<br />
|
2013-05-26 10:03:15 +00:00
|
|
|
The last vote has been given $clockago ago.<br/>
|
2022-02-05 19:56:47 +00:00
|
|
|
During the last 48 hours, {$tab2->votes} votes have been given.";
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2020-09-10 17:29:15 +00:00
|
|
|
/**
|
|
|
|
* @param int $id
|
|
|
|
* @param string $answer
|
|
|
|
* @param User $user
|
|
|
|
* @return bool
|
|
|
|
*/
|
2020-02-08 13:51:46 +00:00
|
|
|
public static function submitVote( $id, $answer, User $user ) {
|
2020-01-28 22:28:04 +00:00
|
|
|
$readonly = MediaWikiServices::getInstance()->getReadOnlyMode()->getReason();
|
|
|
|
|
2020-02-08 13:51:46 +00:00
|
|
|
if ( !$user->isAllowed( 'ajaxpoll-vote' ) || $user->isBot() ) {
|
|
|
|
return self::buildHTML( $id, $user, $readonly );
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 22:28:04 +00:00
|
|
|
if ( $readonly ) {
|
|
|
|
return self::buildHTML( $id, $user, $readonly, '' );
|
|
|
|
}
|
|
|
|
|
2021-09-18 12:40:40 +00:00
|
|
|
$dbw = wfGetDB( DB_PRIMARY );
|
2015-12-08 01:40:49 +00:00
|
|
|
|
2012-03-12 23:56:59 +00:00
|
|
|
if ( $answer != 0 ) {
|
|
|
|
$answer = ++$answer;
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
$row = $dbw->selectRow(
|
2012-03-14 20:28:16 +00:00
|
|
|
'ajaxpoll_vote',
|
2012-03-12 23:56:59 +00:00
|
|
|
'COUNT(*) AS count',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2012-03-12 22:13:51 +00:00
|
|
|
'poll_id' => $id,
|
2020-01-08 18:43:41 +00:00
|
|
|
'poll_actor' => $user->getActorId()
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2012-02-19 19:31:24 +00:00
|
|
|
__METHOD__
|
|
|
|
);
|
2012-03-12 23:56:59 +00:00
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
if ( $row->count > 0 ) {
|
2020-01-08 18:43:41 +00:00
|
|
|
$pollContainerText = self::updateVote( $dbw, $id, $user, $answer );
|
2012-03-12 23:56:59 +00:00
|
|
|
} else {
|
2020-01-08 18:43:41 +00:00
|
|
|
$pollContainerText = self::addVote( $dbw, $id, $user, $answer );
|
2012-03-12 23:56:59 +00:00
|
|
|
}
|
|
|
|
} else { // revoking a vote
|
2020-01-08 18:43:41 +00:00
|
|
|
$pollContainerText = self::revokeVote( $dbw, $id, $user );
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2020-01-28 22:28:04 +00:00
|
|
|
return self::buildHTML( $id, $user, false, '', $pollContainerText );
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
/**
|
|
|
|
* @todo FIXME: these three *vote() methods are kinda sucky.
|
|
|
|
* Ideally they'd return a Status or somesuch and wouldn't take a $dbw param
|
|
|
|
* but the param is right now needed since all methods of this class are static...
|
|
|
|
*
|
|
|
|
* I am not amused by having to do all sorts of weird magic to get around jenkins
|
|
|
|
* being stupid.
|
|
|
|
*
|
2019-06-25 20:19:38 +00:00
|
|
|
* @param IDatabase $dbw Write connection to a database
|
2018-05-12 12:27:22 +00:00
|
|
|
* @param string $id Poll ID
|
2020-01-08 18:43:41 +00:00
|
|
|
* @param User $user User (object) who is voting
|
2018-05-12 12:27:22 +00:00
|
|
|
* @param int $answer Answer option #
|
|
|
|
* @return string Name of an i18n msg to show to the user
|
|
|
|
*/
|
2020-01-08 18:43:41 +00:00
|
|
|
public static function addVote( $dbw, $id, $user, $answer ) {
|
2018-05-12 12:27:22 +00:00
|
|
|
global $wgRequest;
|
|
|
|
$insertQuery = $dbw->insert(
|
|
|
|
'ajaxpoll_vote',
|
|
|
|
[
|
|
|
|
'poll_id' => $id,
|
2020-01-08 18:43:41 +00:00
|
|
|
'poll_actor' => $user->getActorId(),
|
2018-05-12 12:27:22 +00:00
|
|
|
'poll_ip' => $wgRequest->getIP(),
|
|
|
|
'poll_answer' => $answer,
|
2020-02-05 13:43:55 +00:00
|
|
|
'poll_date' => $dbw->timestamp( wfTimestampNow() )
|
2018-05-12 12:27:22 +00:00
|
|
|
],
|
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
return ( $insertQuery ) ? 'ajaxpoll-vote-add' : 'ajaxpoll-vote-error';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-06-25 20:19:38 +00:00
|
|
|
* @param IDatabase $dbw Write connection to a database
|
2018-05-12 12:27:22 +00:00
|
|
|
* @param string $id Poll ID
|
2020-01-08 18:43:41 +00:00
|
|
|
* @param User $user User (object) who is voting
|
2018-05-12 12:27:22 +00:00
|
|
|
* @return string Name of an i18n msg to show to the user
|
|
|
|
*/
|
2020-01-08 18:43:41 +00:00
|
|
|
public static function revokeVote( $dbw, $id, $user ) {
|
2018-05-12 12:27:22 +00:00
|
|
|
$deleteQuery = $dbw->delete(
|
|
|
|
'ajaxpoll_vote',
|
|
|
|
[
|
|
|
|
'poll_id' => $id,
|
2020-01-08 18:43:41 +00:00
|
|
|
'poll_actor' => $user->getActorId()
|
2018-05-12 12:27:22 +00:00
|
|
|
],
|
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
return ( $deleteQuery ) ? 'ajaxpoll-vote-revoked' : 'ajaxpoll-vote-error';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-06-25 20:19:38 +00:00
|
|
|
* @param IDatabase $dbw Write connection to a database
|
2018-05-12 12:27:22 +00:00
|
|
|
* @param string $id Poll ID
|
2020-01-08 18:43:41 +00:00
|
|
|
* @param User $user User (object) who is voting
|
2018-05-12 12:27:22 +00:00
|
|
|
* @param int $answer Answer option #
|
|
|
|
* @return string Name of an i18n msg to show to the user
|
|
|
|
*/
|
2020-01-08 18:43:41 +00:00
|
|
|
public static function updateVote( $dbw, $id, $user, $answer ) {
|
2018-05-12 12:27:22 +00:00
|
|
|
$updateQuery = $dbw->update(
|
|
|
|
'ajaxpoll_vote',
|
|
|
|
[
|
|
|
|
'poll_answer' => $answer,
|
2020-02-05 13:43:55 +00:00
|
|
|
'poll_date' => $dbw->timestamp( wfTimestampNow() )
|
2018-05-12 12:27:22 +00:00
|
|
|
],
|
|
|
|
[
|
|
|
|
'poll_id' => $id,
|
2020-01-08 18:43:41 +00:00
|
|
|
'poll_actor' => $user->getActorId()
|
2018-05-12 12:27:22 +00:00
|
|
|
],
|
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
return ( $updateQuery ) ? 'ajaxpoll-vote-update' : 'ajaxpoll-vote-error';
|
|
|
|
}
|
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
private static function escapeContent( $string ) {
|
|
|
|
return htmlspecialchars( Sanitizer::decodeCharReferences( $string ), ENT_QUOTES );
|
|
|
|
}
|
|
|
|
|
2020-01-28 22:28:04 +00:00
|
|
|
private static function buildHTML( $id, $user, $readonly, $lines = '', $extra_from_ajax = '' ) {
|
2020-02-08 13:51:46 +00:00
|
|
|
global $wgTitle, $wgLang;
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2017-09-01 23:39:28 +00:00
|
|
|
$dbr = wfGetDB( DB_REPLICA );
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
$row = $dbr->selectRow(
|
2012-03-14 20:28:16 +00:00
|
|
|
'ajaxpoll_info',
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'poll_txt', 'poll_date', 'poll_show_results_before_voting' ],
|
|
|
|
[ 'poll_id' => $id ],
|
2012-02-19 19:31:24 +00:00
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
|
|
|
|
if ( empty( $lines ) ) {
|
2022-02-05 19:56:47 +00:00
|
|
|
$lines = explode( "\n", trim( $row->poll_txt ) );
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
if ( $row->poll_show_results_before_voting !== null ) {
|
|
|
|
$showResultsBeforeVoting = ( $row->poll_show_results_before_voting === '1' );
|
2013-05-26 10:03:15 +00:00
|
|
|
} else {
|
2020-02-08 13:51:46 +00:00
|
|
|
$showResultsBeforeVoting = $user->isAllowed( 'ajaxpoll-view-results-before-vote' );
|
2013-05-26 10:03:15 +00:00
|
|
|
}
|
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
$start_date = $row->poll_date;
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2012-03-12 22:13:51 +00:00
|
|
|
$q = $dbr->select(
|
2012-03-14 20:28:16 +00:00
|
|
|
'ajaxpoll_vote',
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'poll_answer', 'count' => 'COUNT(*)' ],
|
|
|
|
[ 'poll_id' => $id ],
|
2012-02-19 19:31:24 +00:00
|
|
|
__METHOD__,
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'GROUP BY' => 'poll_answer' ]
|
2012-02-19 19:31:24 +00:00
|
|
|
);
|
|
|
|
|
2016-05-09 23:15:51 +00:00
|
|
|
$poll_result = [];
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2015-11-05 20:45:46 +00:00
|
|
|
foreach ( $q as $row ) {
|
|
|
|
$poll_result[$row->poll_answer] = $row->count;
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
$amountOfVotes = array_sum( $poll_result );
|
|
|
|
|
|
|
|
// Did we vote?
|
2013-05-26 10:03:15 +00:00
|
|
|
$userVoted = false;
|
|
|
|
|
2022-02-05 19:56:47 +00:00
|
|
|
$row = $dbr->selectRow(
|
2012-03-14 20:28:16 +00:00
|
|
|
'ajaxpoll_vote',
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'poll_answer', 'poll_date' ],
|
|
|
|
[
|
2012-03-12 22:13:51 +00:00
|
|
|
'poll_id' => $id,
|
2020-01-08 18:43:41 +00:00
|
|
|
'poll_actor' => $user->getActorId()
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2012-02-19 19:31:24 +00:00
|
|
|
__METHOD__
|
|
|
|
);
|
|
|
|
|
2015-11-05 20:45:46 +00:00
|
|
|
if ( $row ) {
|
2022-02-05 19:56:47 +00:00
|
|
|
$ts = wfTimestamp( TS_MW, $row->poll_date );
|
2013-05-26 07:33:05 +00:00
|
|
|
$ourLastVoteDate = wfMessage(
|
2012-02-19 19:31:24 +00:00
|
|
|
'ajaxpoll-your-vote',
|
2022-02-05 19:56:47 +00:00
|
|
|
$lines[$row->poll_answer - 1],
|
2014-12-28 19:23:39 +00:00
|
|
|
$wgLang->timeanddate( $ts, true /* adjust? */ ),
|
|
|
|
$wgLang->date( $ts, true /* adjust? */ ),
|
|
|
|
$wgLang->time( $ts, true /* adjust? */ )
|
2013-05-26 07:33:05 +00:00
|
|
|
)->escaped();
|
2013-05-26 10:03:15 +00:00
|
|
|
$userVoted = true;
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
$ret = '';
|
2012-02-19 19:31:24 +00:00
|
|
|
if ( is_object( $wgTitle ) ) {
|
2015-09-29 20:40:24 +00:00
|
|
|
if ( !empty( $extra_from_ajax ) ) {
|
2013-06-04 20:01:09 +00:00
|
|
|
$style = 'display:inline-block';
|
2013-05-26 07:33:05 +00:00
|
|
|
$ajaxMessage = wfMessage( $extra_from_ajax )->escaped();
|
2012-02-19 19:31:24 +00:00
|
|
|
} else {
|
2013-06-04 20:01:09 +00:00
|
|
|
$style = 'display:none';
|
2012-02-19 19:31:24 +00:00
|
|
|
$ajaxMessage = '';
|
|
|
|
}
|
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
$ret = Html::openElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'id' => 'ajaxpoll-id-' . $id,
|
|
|
|
'class' => 'ajaxpoll'
|
2016-05-09 23:15:51 +00:00
|
|
|
]
|
2013-06-04 20:01:09 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
$ret .= Html::element( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'id' => 'ajaxpoll-ajax-' . $id,
|
|
|
|
'class' => 'ajaxpoll-ajax',
|
|
|
|
'style' => $style
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
$ajaxMessage
|
|
|
|
);
|
|
|
|
|
|
|
|
$ret .= Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'class' => 'ajaxpoll-question' ],
|
2013-06-04 20:01:09 +00:00
|
|
|
self::escapeContent( $lines[0] )
|
|
|
|
);
|
|
|
|
|
|
|
|
// Different messages depending whether the user has already voted
|
|
|
|
// or has not voted, or is entitled to vote
|
2012-03-10 09:26:52 +00:00
|
|
|
|
2012-03-13 01:04:59 +00:00
|
|
|
$canRevoke = false;
|
|
|
|
|
2020-02-08 13:51:46 +00:00
|
|
|
if ( $user->isAllowed( 'ajaxpoll-vote' ) ) {
|
2022-02-21 14:22:13 +00:00
|
|
|
if ( isset( $row->poll_answer ) ) {
|
2012-03-12 23:56:59 +00:00
|
|
|
$message = $ourLastVoteDate;
|
2012-03-13 01:04:59 +00:00
|
|
|
$canRevoke = true;
|
2013-05-26 07:33:05 +00:00
|
|
|
$lines[] = wfMessage( 'ajaxpoll-revoke-vote' )->text();
|
2012-03-12 23:56:59 +00:00
|
|
|
} else {
|
2013-05-26 10:03:15 +00:00
|
|
|
if ( $showResultsBeforeVoting ) {
|
|
|
|
$message = wfMessage( 'ajaxpoll-no-vote' )->text();
|
|
|
|
} else {
|
|
|
|
$message = wfMessage( 'ajaxpoll-no-vote-results-after-voting' )->text();
|
|
|
|
}
|
2012-03-12 23:56:59 +00:00
|
|
|
}
|
2012-03-10 09:26:52 +00:00
|
|
|
} else {
|
2013-05-26 07:33:05 +00:00
|
|
|
$message = wfMessage( 'ajaxpoll-vote-permission' )->text();
|
2012-03-10 09:26:52 +00:00
|
|
|
}
|
2013-05-26 10:03:15 +00:00
|
|
|
|
2020-02-08 13:51:46 +00:00
|
|
|
if ( !$user->isAllowed( 'ajaxpoll-view-results' ) ) {
|
2018-05-12 12:27:22 +00:00
|
|
|
$message .= '<br/>' . wfMessage( 'ajaxpoll-view-results-permission' )->text();
|
2013-05-26 10:03:15 +00:00
|
|
|
} elseif ( !$userVoted
|
2020-02-08 13:51:46 +00:00
|
|
|
&& !$user->isAllowed( 'ajaxpoll-view-results-before-vote' )
|
2015-09-29 20:40:24 +00:00
|
|
|
&& !$showResultsBeforeVoting
|
|
|
|
) {
|
2020-02-08 13:51:46 +00:00
|
|
|
if ( $user->isAllowed( 'ajaxpoll-vote' ) ) {
|
2018-05-12 12:27:22 +00:00
|
|
|
$message .= '<br/>' . wfMessage( 'ajaxpoll-view-results-before-vote-permission' )->text();
|
2015-09-29 20:40:24 +00:00
|
|
|
} else {
|
2018-05-12 12:27:22 +00:00
|
|
|
$message .= '<br/>' . wfMessage( 'ajaxpoll-view-results-permission' )->text();
|
2015-09-29 20:40:24 +00:00
|
|
|
}
|
2013-05-26 10:03:15 +00:00
|
|
|
}
|
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
$ret .= Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'class' => 'ajaxpoll-misc' ],
|
2013-06-04 20:01:09 +00:00
|
|
|
$message
|
|
|
|
);
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
$ret .= Html::rawElement( 'form',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'method' => 'post',
|
|
|
|
'action' => $wgTitle->getLocalURL(),
|
|
|
|
'id' => 'ajaxpoll-answer-id-' . $id
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::element( 'input',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'type' => 'hidden',
|
|
|
|
'name' => 'ajaxpoll-post-id',
|
|
|
|
'value' => $id
|
2016-05-09 23:15:51 +00:00
|
|
|
]
|
2013-06-04 20:01:09 +00:00
|
|
|
)
|
|
|
|
);
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2015-09-29 20:40:24 +00:00
|
|
|
$linesCount = count( $lines );
|
|
|
|
for ( $i = 1; $i < $linesCount; $i++ ) {
|
|
|
|
$vote = !( $canRevoke && ( $i == $linesCount - 1 ) );
|
2012-03-13 01:04:59 +00:00
|
|
|
|
2012-03-15 07:46:55 +00:00
|
|
|
// answers are counted from 1 ... n
|
|
|
|
// last answer is pseudo-answer for "I want to revoke vote"
|
|
|
|
// and becomes answer number 0
|
|
|
|
|
|
|
|
$answer = ( $vote ) ? $i : 0;
|
2018-05-12 12:27:22 +00:00
|
|
|
$xid = $id . '-' . $answer;
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
if ( ( $amountOfVotes !== 0 ) && ( isset( $poll_result[$i + 1] ) ) ) {
|
|
|
|
$pollResult = $poll_result[$i + 1];
|
|
|
|
$percent = round( $pollResult * 100 / $amountOfVotes, 2 );
|
2012-02-19 19:31:24 +00:00
|
|
|
} else {
|
2013-06-04 20:01:09 +00:00
|
|
|
$pollResult = 0;
|
|
|
|
$percent = 0;
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
$border = ( $percent == 0 ) ? ' border:0;' : '';
|
2022-02-21 14:22:13 +00:00
|
|
|
$isOurVote = ( isset( $row->poll_answer ) && ( $row->poll_answer - 1 == $i ) );
|
2013-06-04 20:01:09 +00:00
|
|
|
|
|
|
|
$resultBar = '';
|
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
if (
|
2020-02-08 13:51:46 +00:00
|
|
|
$user->isAllowed( 'ajaxpoll-view-results' ) &&
|
2018-05-12 12:27:22 +00:00
|
|
|
( $showResultsBeforeVoting || ( !$showResultsBeforeVoting && $userVoted ) ) &&
|
|
|
|
$vote
|
2015-09-29 20:40:24 +00:00
|
|
|
) {
|
2013-06-04 20:01:09 +00:00
|
|
|
$resultBar = Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'class' => 'ajaxpoll-answer-vote' . ( $isOurVote ? ' ajaxpoll-our-vote' : '' )
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::rawElement( 'span',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'title' => wfMessage( 'ajaxpoll-percent-votes' )->numParams( $percent )->escaped()
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
self::escapeContent( $pollResult )
|
|
|
|
) .
|
|
|
|
Html::element( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'style' => 'width:' . $percent . '%;' . $border
|
2016-05-09 23:15:51 +00:00
|
|
|
]
|
2013-06-04 20:01:09 +00:00
|
|
|
)
|
|
|
|
);
|
2013-05-26 10:03:15 +00:00
|
|
|
}
|
|
|
|
|
2020-02-08 13:51:46 +00:00
|
|
|
if ( !$readonly && $user->isAllowed( 'ajaxpoll-vote' ) ) {
|
2013-06-04 20:01:09 +00:00
|
|
|
$ret .= Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'id' => 'ajaxpoll-answer-' . $xid,
|
|
|
|
'class' => 'ajaxpoll-answer',
|
|
|
|
'poll' => $id,
|
|
|
|
'answer' => $answer,
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'class' => 'ajaxpoll-answer-name' . ( $vote ? ' ajaxpoll-answer-name-revoke' : '' )
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::rawElement( 'label',
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'for' => 'ajaxpoll-post-answer-' . $xid ],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::element( 'input',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'type' => 'radio',
|
|
|
|
'id' => 'ajaxpoll-post-answer-' . $xid,
|
|
|
|
'name' => 'ajaxpoll-post-answer-' . $id,
|
|
|
|
'value' => $answer,
|
2018-05-12 12:27:22 +00:00
|
|
|
'checked' => $isOurVote ? 'true' : false,
|
2016-05-09 23:15:51 +00:00
|
|
|
]
|
2013-06-04 20:01:09 +00:00
|
|
|
) .
|
|
|
|
self::escapeContent( $lines[$i] )
|
|
|
|
)
|
|
|
|
) .
|
|
|
|
$resultBar
|
|
|
|
);
|
2012-03-10 09:26:52 +00:00
|
|
|
} else {
|
2020-02-08 13:51:46 +00:00
|
|
|
if ( !$user->isAllowed( 'ajaxpoll-vote' ) ) {
|
2020-01-28 22:28:04 +00:00
|
|
|
$disabledReason = wfMessage( 'ajaxpoll-vote-permission' )->escaped();
|
|
|
|
} else {
|
|
|
|
$disabledReason = wfMessage( 'ajaxpoll-readonly', $readonly )->escaped();
|
|
|
|
}
|
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
$ret .= Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'id' => 'ajaxpoll-answer-' . $xid,
|
|
|
|
'class' => 'ajaxpoll-answer',
|
|
|
|
'poll' => $id,
|
|
|
|
'answer' => $answer
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'class' => 'ajaxpoll-answer-name'
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::rawElement( 'label',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'for' => 'ajaxpoll-post-answer-' . $xid,
|
2020-01-28 22:28:04 +00:00
|
|
|
'id' => 'ajaxpoll-label-disabled',
|
|
|
|
'title' => $disabledReason
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::element( 'input',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'disabled' => 'disabled',
|
|
|
|
'type' => 'radio',
|
|
|
|
'id' => 'ajaxpoll-post-answer-' . $xid,
|
|
|
|
'name' => 'ajaxpoll-post-answer-' . $id,
|
|
|
|
'value' => $answer
|
2016-05-09 23:15:51 +00:00
|
|
|
]
|
2013-06-04 20:01:09 +00:00
|
|
|
) .
|
|
|
|
self::escapeContent( $lines[$i] )
|
|
|
|
)
|
2020-01-28 22:28:04 +00:00
|
|
|
) .
|
2013-06-04 20:01:09 +00:00
|
|
|
$resultBar
|
|
|
|
);
|
2012-03-10 09:26:52 +00:00
|
|
|
}
|
|
|
|
}
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
$ret .= Xml::closeElement( 'form' );
|
2012-02-19 19:31:24 +00:00
|
|
|
|
|
|
|
// Display information about the poll (creation date, amount of votes)
|
2013-05-26 07:33:05 +00:00
|
|
|
$pollSummary = wfMessage(
|
2012-02-19 19:31:24 +00:00
|
|
|
'ajaxpoll-info',
|
|
|
|
$amountOfVotes, // amount of votes
|
|
|
|
$wgLang->timeanddate( wfTimestamp( TS_MW, $start_date ), true /* adjust? */ )
|
2013-05-26 07:33:05 +00:00
|
|
|
)->text();
|
2012-02-19 19:31:24 +00:00
|
|
|
|
2013-06-04 20:01:09 +00:00
|
|
|
$ret .= Html::rawElement( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[
|
2013-06-04 20:01:09 +00:00
|
|
|
'id' => 'ajaxpoll-info-' . $id,
|
|
|
|
'class' => 'ajaxpoll-info'
|
2016-05-09 23:15:51 +00:00
|
|
|
],
|
2013-06-04 20:01:09 +00:00
|
|
|
self::escapeContent( $pollSummary ) .
|
2018-05-12 12:27:22 +00:00
|
|
|
// @todo Just why are we exposing this in the UI, again?
|
|
|
|
// It's ugly and unnecessary even though technically hidden by CSS.
|
2013-06-04 20:01:09 +00:00
|
|
|
Html::element( 'div',
|
2016-05-09 23:15:51 +00:00
|
|
|
[ 'class' => 'ajaxpoll-id-info' ],
|
2013-06-04 20:01:09 +00:00
|
|
|
'poll-id ' . $id
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
$ret .= Html::closeElement( 'div' ) .
|
|
|
|
Html::element( 'br' );
|
2012-02-19 19:31:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
/**
|
|
|
|
* Adds the two new required database tables into the database when the
|
|
|
|
* end-user (sysadmin) runs /maintenance/update.php
|
|
|
|
* (the core database updater script) and performs other DB updates, such as
|
|
|
|
* the renaming of tables, if upgrading from an older version of this extension.
|
|
|
|
*
|
|
|
|
* @param DatabaseUpdater $updater
|
|
|
|
*/
|
|
|
|
public static function onLoadExtensionSchemaUpdates( $updater ) {
|
|
|
|
$db = $updater->getDB();
|
2013-05-26 10:03:15 +00:00
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
$patchPath = __DIR__ . '/../sql/';
|
2020-01-27 02:58:11 +00:00
|
|
|
if ( $db->getType() == 'postgres' ) {
|
|
|
|
$patchPath .= 'postgres/';
|
|
|
|
}
|
2012-03-14 20:19:16 +00:00
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
if ( $db->tableExists( 'poll_info' ) ) {
|
|
|
|
# poll_info.poll_title field was dropped in AJAXPoll version 1.72
|
|
|
|
$updater->dropExtensionField(
|
|
|
|
'poll_info',
|
|
|
|
'poll_title',
|
|
|
|
$patchPath . 'drop-field--poll_info-poll_title.sql'
|
|
|
|
);
|
|
|
|
$updater->addExtensionTable(
|
|
|
|
'ajaxpoll_info',
|
|
|
|
$patchPath . 'rename-table--poll_info.sql'
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$updater->addExtensionTable(
|
|
|
|
'ajaxpoll_info',
|
|
|
|
$patchPath . 'create-table--ajaxpoll_info.sql'
|
|
|
|
);
|
|
|
|
}
|
2013-05-26 10:03:15 +00:00
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
if ( $db->tableExists( 'ajaxpoll_info' ) ) {
|
|
|
|
$updater->addExtensionField(
|
|
|
|
'ajaxpoll_info',
|
|
|
|
'poll_show_results_before_voting',
|
|
|
|
$patchPath . 'add-field--ajaxpoll_info-poll_show_results_before_voting.sql'
|
|
|
|
);
|
2012-03-14 20:19:16 +00:00
|
|
|
}
|
2012-03-14 21:43:56 +00:00
|
|
|
|
2018-05-12 12:27:22 +00:00
|
|
|
if ( $db->tableExists( 'poll_vote' ) ) {
|
|
|
|
$updater->addExtensionTable(
|
|
|
|
'poll_vote',
|
|
|
|
$patchPath . 'rename-table--poll_vote.sql'
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$updater->addExtensionTable(
|
|
|
|
'ajaxpoll_vote',
|
|
|
|
$patchPath . 'create-table--ajaxpoll_vote.sql'
|
|
|
|
);
|
|
|
|
}
|
2020-01-08 18:43:41 +00:00
|
|
|
|
|
|
|
// Actor support
|
|
|
|
|
|
|
|
// 1) add new actor column
|
2021-04-04 18:13:02 +00:00
|
|
|
$updater->addExtensionField(
|
|
|
|
'ajaxpoll_vote',
|
|
|
|
'poll_actor',
|
|
|
|
$patchPath . 'add-field-ajaxpoll_vote-poll_actor.sql'
|
|
|
|
);
|
2020-01-08 18:43:41 +00:00
|
|
|
|
|
|
|
// 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.
|
2024-07-10 07:40:34 +00:00
|
|
|
// 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
|
2020-01-08 18:43:41 +00:00
|
|
|
$updater->addExtensionUpdate( [
|
|
|
|
'runMaintenance',
|
|
|
|
'MigrateOldAJAXPollUserColumnsToActor',
|
2024-07-10 07:40:34 +00:00
|
|
|
'../maintenance/migrateOldAJAXPollUserColumnsToActor.php'
|
2020-01-08 18:43:41 +00:00
|
|
|
] );
|
|
|
|
|
|
|
|
// 3) drop the now unused column
|
2021-04-04 18:13:02 +00:00
|
|
|
$updater->dropExtensionField(
|
|
|
|
'ajaxpoll_vote',
|
|
|
|
'poll_user',
|
|
|
|
$patchPath . 'drop-field-poll_user-ajaxpoll_vote.sql'
|
|
|
|
);
|
2012-03-14 20:19:16 +00:00
|
|
|
}
|
2015-09-29 20:40:24 +00:00
|
|
|
}
|