Use PHP DateInputWidget in Contribs and use for range filtering
* Add two DateInputWidgets to Special:Contributions, one for start and one for end ** If start input is empty but end input is not, display edits up to end input, and vice versa ** If both inputs are specified, display edits between the two dates ** If both inputs are empty, no date range is used * Legacy options (year=/month=) are converted to use for the end timestamp, so URLs with them should still work. * Unit tests! Bug: T120733 Change-Id: Id15f2b2ce2954fe98dfbbb7b0e86c0e4e5713f5e
This commit is contained in:
parent
4b110c881c
commit
b66888733c
5 changed files with 160 additions and 22 deletions
|
|
@ -40,8 +40,11 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
$out->addModuleStyles( [
|
||||
'mediawiki.special',
|
||||
'mediawiki.special.changeslist',
|
||||
'mediawiki.widgets.DateInputWidget',
|
||||
] );
|
||||
$out->addModules( 'mediawiki.special.contributions' );
|
||||
$this->addHelpLink( 'Help:User contributions' );
|
||||
$out->enableOOUI();
|
||||
|
||||
$this->opts = [];
|
||||
$request = $this->getRequest();
|
||||
|
|
@ -130,8 +133,12 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
$this->opts['year'] = '';
|
||||
$this->opts['month'] = '';
|
||||
} else {
|
||||
$this->opts['year'] = $request->getIntOrNull( 'year' );
|
||||
$this->opts['month'] = $request->getIntOrNull( 'month' );
|
||||
$this->opts['year'] = $request->getVal( 'year' );
|
||||
$this->opts['month'] = $request->getVal( 'month' );
|
||||
|
||||
$this->opts['start'] = $request->getVal( 'start' );
|
||||
$this->opts['end'] = $request->getVal( 'end' );
|
||||
$this->opts = SpecialContributions::processDateFilter( $this->opts );
|
||||
}
|
||||
|
||||
$feedType = $request->getVal( 'feed' );
|
||||
|
|
@ -190,8 +197,8 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
'contribs' => $this->opts['contribs'],
|
||||
'namespace' => $this->opts['namespace'],
|
||||
'tagfilter' => $this->opts['tagfilter'],
|
||||
'year' => $this->opts['year'],
|
||||
'month' => $this->opts['month'],
|
||||
'start' => $this->opts['start'],
|
||||
'end' => $this->opts['end'],
|
||||
'deletedOnly' => $this->opts['deletedOnly'],
|
||||
'topOnly' => $this->opts['topOnly'],
|
||||
'newOnly' => $this->opts['newOnly'],
|
||||
|
|
@ -432,12 +439,12 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
$this->opts['contribs'] = 'user';
|
||||
}
|
||||
|
||||
if ( !isset( $this->opts['year'] ) ) {
|
||||
$this->opts['year'] = '';
|
||||
if ( !isset( $this->opts['start'] ) ) {
|
||||
$this->opts['start'] = '';
|
||||
}
|
||||
|
||||
if ( !isset( $this->opts['month'] ) ) {
|
||||
$this->opts['month'] = '';
|
||||
if ( !isset( $this->opts['end'] ) ) {
|
||||
$this->opts['end'] = '';
|
||||
}
|
||||
|
||||
if ( $this->opts['contribs'] == 'newbie' ) {
|
||||
|
|
@ -478,6 +485,8 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
'contribs',
|
||||
'year',
|
||||
'month',
|
||||
'start',
|
||||
'end',
|
||||
'topOnly',
|
||||
'newOnly',
|
||||
'hideMinor',
|
||||
|
|
@ -652,15 +661,32 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
implode( '', $filters )
|
||||
);
|
||||
|
||||
$dateSelectionAndSubmit = Xml::tags( 'div', [],
|
||||
Xml::dateMenu(
|
||||
$this->opts['year'] === '' ? MWTimestamp::getInstance()->format( 'Y' ) : $this->opts['year'],
|
||||
$this->opts['month']
|
||||
) . ' ' .
|
||||
Html::submitButton(
|
||||
$this->msg( 'sp-contributions-submit' )->text(),
|
||||
[ 'class' => 'mw-submit' ], [ 'mw-ui-progressive' ]
|
||||
)
|
||||
$dateRangeSelection = Html::rawElement(
|
||||
'div',
|
||||
[],
|
||||
Xml::label( wfMessage( 'date-range-from' )->text(), 'mw-date-start' ) . ' ' .
|
||||
new \Mediawiki\Widget\DateInputWidget( [
|
||||
'infusable' => true,
|
||||
'id' => 'mw-date-start',
|
||||
'name' => 'start',
|
||||
'value' => $this->opts['start'],
|
||||
'longDisplayFormat' => true,
|
||||
] ) . '<br>' .
|
||||
Xml::label( wfMessage( 'date-range-to' )->text(), 'mw-date-end' ) . ' ' .
|
||||
new \Mediawiki\Widget\DateInputWidget( [
|
||||
'infusable' => true,
|
||||
'id' => 'mw-date-end',
|
||||
'name' => 'end',
|
||||
'value' => $this->opts['end'],
|
||||
'longDisplayFormat' => true,
|
||||
] )
|
||||
);
|
||||
|
||||
$submit = Xml::tags( 'div', [],
|
||||
Html::submitButton(
|
||||
$this->msg( 'sp-contributions-submit' )->text(),
|
||||
[ 'class' => 'mw-submit' ], [ 'mw-ui-progressive' ]
|
||||
)
|
||||
);
|
||||
|
||||
$form .= Xml::fieldset(
|
||||
|
|
@ -669,7 +695,8 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
$namespaceSelection .
|
||||
$filterSelection .
|
||||
$extraOptions .
|
||||
$dateSelectionAndSubmit,
|
||||
$dateRangeSelection .
|
||||
$submit,
|
||||
[ 'class' => 'mw-contributions-table' ]
|
||||
);
|
||||
|
||||
|
|
@ -701,6 +728,46 @@ class SpecialContributions extends IncludableSpecialPage {
|
|||
return UserNamePrefixSearch::search( 'public', $search, $limit, $offset );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up date filter options, given request data.
|
||||
*
|
||||
* @param array $opts Options array
|
||||
* @return array Options array with processed start and end date filter options
|
||||
*/
|
||||
public static function processDateFilter( $opts ) {
|
||||
$start = $opts['start'] ?: '';
|
||||
$end = $opts['end'] ?: '';
|
||||
$year = $opts['year'] ?: '';
|
||||
$month = $opts['month'] ?: '';
|
||||
|
||||
if ( $start !== '' && $end !== '' &&
|
||||
$start > $end
|
||||
) {
|
||||
$temp = $start;
|
||||
$start = $end;
|
||||
$end = $temp;
|
||||
}
|
||||
|
||||
// If year/month legacy filtering options are set, convert them to display the new stamp
|
||||
if ( $year !== '' || $month !== '' ) {
|
||||
// Reuse getDateCond logic, but subtract a day because
|
||||
// the endpoints of our date range appear inclusive
|
||||
// but the internal end offsets are always exclusive
|
||||
$legacyTimestamp = ReverseChronologicalPager::getOffsetDate( $year, $month );
|
||||
$legacyDateTime = new DateTime( $legacyTimestamp->getTimestamp( TS_ISO_8601 ) );
|
||||
$legacyDateTime = $legacyDateTime->modify( '-1 day' );
|
||||
|
||||
// Clear the new timestamp range options if used and
|
||||
// replace with the converted legacy timestamp
|
||||
$start = '';
|
||||
$end = $legacyDateTime->format( 'Y-m-d' );
|
||||
}
|
||||
|
||||
$opts['start'] = $start;
|
||||
$opts['end'] = $end;
|
||||
return $opts;
|
||||
}
|
||||
|
||||
protected function getGroupName() {
|
||||
return 'users';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ use Wikimedia\Rdbms\ResultWrapper;
|
|||
use Wikimedia\Rdbms\FakeResultWrapper;
|
||||
use Wikimedia\Rdbms\IDatabase;
|
||||
|
||||
class ContribsPager extends ReverseChronologicalPager {
|
||||
class ContribsPager extends RangeChronologicalPager {
|
||||
|
||||
public $mDefaultDirection = IndexPager::DIR_DESCENDING;
|
||||
public $messages;
|
||||
|
|
@ -76,9 +76,16 @@ class ContribsPager extends ReverseChronologicalPager {
|
|||
$this->newOnly = !empty( $options['newOnly'] );
|
||||
$this->hideMinor = !empty( $options['hideMinor'] );
|
||||
|
||||
$year = isset( $options['year'] ) ? $options['year'] : false;
|
||||
$month = isset( $options['month'] ) ? $options['month'] : false;
|
||||
$this->getDateCond( $year, $month );
|
||||
// Date filtering: use timestamp if available
|
||||
$startTimestamp = '';
|
||||
$endTimestamp = '';
|
||||
if ( $options['start'] ) {
|
||||
$startTimestamp = $options['start'] . ' 00:00:00';
|
||||
}
|
||||
if ( $options['end'] ) {
|
||||
$endTimestamp = $options['end'] . ' 23:59:59';
|
||||
}
|
||||
$this->getDateRangeCond( $startTimestamp, $endTimestamp );
|
||||
|
||||
// Most of this code will use the 'contributions' group DB, which can map to replica DBs
|
||||
// with extra user based indexes or partioning by user. The additional metadata
|
||||
|
|
|
|||
|
|
@ -1958,6 +1958,13 @@ return [
|
|||
'mediawiki.special.comparepages.styles' => [
|
||||
'styles' => 'resources/src/mediawiki.special/mediawiki.special.comparepages.styles.less',
|
||||
],
|
||||
'mediawiki.special.contributions' => [
|
||||
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.contributions.js',
|
||||
'dependencies' => [
|
||||
'mediawiki.widgets.DateInputWidget',
|
||||
'mediawiki.jqueryMsg',
|
||||
]
|
||||
],
|
||||
'mediawiki.special.edittags' => [
|
||||
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.edittags.js',
|
||||
'dependencies' => [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
/* jshint -W024*/
|
||||
( function ( mw, $ ) {
|
||||
$( function () {
|
||||
mw.widgets.DateInputWidget.static.infuse( 'mw-date-start' );
|
||||
mw.widgets.DateInputWidget.static.infuse( 'mw-date-end' );
|
||||
} );
|
||||
}( mediaWiki, jQuery ) );
|
||||
50
tests/phpunit/includes/specials/SpecialContributionsTest.php
Normal file
50
tests/phpunit/includes/specials/SpecialContributionsTest.php
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group Database
|
||||
*/
|
||||
class SpecialContributionsTest extends \PHPUnit_Framework_TestCase {
|
||||
/**
|
||||
* @dataProvider dateFilterOptionProcessingProvider
|
||||
* @param array $inputOpts Input options
|
||||
* @param array $expectedOpts Expected options
|
||||
*/
|
||||
public function testDateFilterOptionProcessing( $inputOpts, $expectedOpts ) {
|
||||
$this->assertArraySubset( $expectedOpts, SpecialContributions::processDateFilter( $inputOpts ) );
|
||||
}
|
||||
|
||||
public static function dateFilterOptionProcessingProvider() {
|
||||
return [
|
||||
[ [ 'start' => '2016-05-01',
|
||||
'end' => '2016-06-01',
|
||||
'year' => null,
|
||||
'month' => null ],
|
||||
[ 'start' => '2016-05-01',
|
||||
'end' => '2016-06-01' ] ],
|
||||
[ [ 'start' => '2016-05-01',
|
||||
'end' => '2016-06-01',
|
||||
'year' => '',
|
||||
'month' => '' ],
|
||||
[ 'start' => '2016-05-01',
|
||||
'end' => '2016-06-01' ] ],
|
||||
[ [ 'start' => '2016-05-01',
|
||||
'end' => '2016-06-01',
|
||||
'year' => '2012',
|
||||
'month' => '5' ],
|
||||
[ 'start' => '',
|
||||
'end' => '2012-05-31' ] ],
|
||||
[ [ 'start' => '',
|
||||
'end' => '',
|
||||
'year' => '2012',
|
||||
'month' => '5' ],
|
||||
[ 'start' => '',
|
||||
'end' => '2012-05-31' ] ],
|
||||
[ [ 'start' => '',
|
||||
'end' => '',
|
||||
'year' => '2012',
|
||||
'month' => '' ],
|
||||
[ 'start' => '',
|
||||
'end' => '2012-12-31' ] ],
|
||||
];
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue