Difference between revisions 263296 and 263297 on ptwikibooks/**
* Adds two links on pages like [[Special:AbuseLog/123]] to mark log entries as 'correct' or 'false positive'
* (workaround for [[bugzilla:28213]]
* @author: [[User:Helder.wiki]]
* @tracking: [[Special:GlobalUsage/User:Helder.wiki/Tools/AbuseLogStatus.js]] ([[File:User:Helder.wiki/Tools/AbuseLogStatus.js]])
*/
/*jshint browser: true, camelcase: false, curly: true, eqeqeq: true, immed: true, latedef: true, newcap: true, noarg: true, noempty: true, nonew: true, quotmark: true, undef: true, unused: true, strict: true, trailing: true, maxlen: 130, laxbreak: true, devel: true, evil: true, onevar: true */
/*global jQuery, mediaWiki */
( function ( mw, $ ) {
'use strict';
/* Translatable strings */
mw.messages.set( {
'al-page-title': 'Wikipédia:Filtro_de_edições/Análise/$1/Registros',
'al-summary': 'Status do registro [[Special:AbuseLog/$1|$1]]: $2' +
' (edição feita com [[Special:PermaLink/36666969#Scripts|um script]])',
'al-correct-template': '*{' + '{Ação|$1}}\n',
'al-problem-template': '*{' + '{Ação|$1|erro=sim}}\n',
'al-correct-template-with-note': '*{' + '{Ação|$1|nota=$2}}\n',
'al-problem-template-with-note': '*{' + '{Ação|$1|erro=sim|nota=$2}}\n',
// Keep this synced with the regex from [[User:Helder.wiki/Tools/AbuseFilterStats.js]]
'al-template-regex': '\\* *\\{\\{ *[Aa]ção *\\|(?:.*?\\D)?($1)(?:\\D.*?)?\\}\\} *(?:\\n|$)',
'al-analysis-page-regex': '^Wikipédia:Filtro de edições\\/Análise\\/(\\d+/\\d+)\\/Registros$',
'al-page-header': '{' + '{Lista de falsos positivos (cabeçalho)}}\n\n',
'al-section-title': 'Filtro $1',
'al-page-edit-success': '<p>A página <a href="$1">foi editada</a>.</p>',
'al-page-edit-conflict': 'Foi detectado um conflito entre edições. Por favor, tente novamente.',
'al-page-edit-error': 'Houve um erro ao tentar editar ($1). Por favor, tente novamente.',
'al-page-edit-error-unknown': 'Houve um erro desconhecido ao tentar editar. Por favor, tente novamente.',
'al-date-error': 'O script só funciona se o formato das datas não for alterado nas preferências.',
'al-page-content-error': 'A página de análises ainda não possui uma seção para este filtro ($1). ' +
'Crie manualmente as seções de cada filtro antes de enviar uma nova análise.',
'al-filter-count-error': 'Houve um erro ao tentar determinar quantos filtros existem atualmente ($1). ' +
'Crie manualmente a página de análises com uma seção para cada filtro antes de enviar uma ' +
'nova análise.',
'al-log-false-positive': 'Um editor já identificou que este registro foi um falso positivo',
'al-log-correct': 'Um editor já identificou que este registro estava correto',
'al-log-false-positive-note': 'Um editor já identificou que este registro foi um falso positivo: $1',
'al-log-correct-note': 'Um editor já identificou que este registro estava correto: $1',
'al-header': 'Análise',
'al-question': 'Este filtro deveria ter detectado esta ação?',
'al-specific-question': 'Foi correto classificar esta ação como "$1"?',
'al-correct-description': 'Marcar este registro como correto',
'al-yes': 'Sim',
'al-correct': 'Correto',
'al-incorrect-description': 'Marcar este registro como falso positivo',
'al-no': 'Não',
'al-incorrect': 'Falso positivo',
'al-placeholder': 'Observação sobre esta ação (se precisar)',
'al-submit': 'Enviar',
'al-submit-description': 'Enviar a sua análise (editará automaticamente a página apropriada)'
} );
var api, filter, revision, reTemplate, reDetailsPage, reFilterLink,
curLogs = {};
function getPeriodFromTimestamp( ts ){
var match, month,
reDateNoPreference = /((?:jan|fever)eiro|março|abril|maio|ju[nl]ho|agosto|(?:setem|outu|novem|dezem)bro) de (\d{4})/;
match = ts.match( reDateNoPreference );
if( match ){
month = $.inArray( match[1], mw.config.get( 'wgMonthNames' ) );
if ( month < 10){
month = '0' + month;
}
return match[2] + '/' + month;
}
mw.notify( mw.msg( 'al-date-error' ), {
autoHide: false,
tag: 'status'
} );
return false;
}
function doEdit ( params ){
api.post( params )
.done( function( data ) {
var edit = data.edit,
link;
if ( edit && edit.result && edit.result === 'Success' ) {
link = mw.util.wikiGetlink( edit.title ) +
'?diff=' + edit.newrevid;
mw.notify( $( mw.msg( 'al-page-edit-success', link ) ), {
autoHide: false,
tag: 'status'
} );
} else {
mw.notify( mw.msg( 'al-page-edit-error-unknown' ), {
autoHide: false,
tag: 'status'
} );
}
} )
.fail( function( code ){
if( code === 'editconflict' ){
// TODO: Try again automatically (and no not remove the spinner during the process)!
mw.notify( mw.msg( 'al-page-edit-conflict' ), {
autoHide: false,
tag: 'status'
} );
return;
}
mw.notify( mw.msg( 'al-page-edit-error', code ), {
autoHide: false,
tag: 'status'
} );
} )
.always( function(){
$.removeSpinner( 'af-status-spinner' );
$( '#al-submit' ).removeAttr( 'disabled' );
} );
}
function onClick (){
var note, period,
falsePositive = $( 'input[type="radio"]:checked' ).val() !== 'correct',
defineStatus = function ( data ){
var template, start, text,
editParams = {
action: 'edit',
title: mw.msg( 'al-page-title', period ),
section: filter,
summary: mw.msg(
'al-summary',
revision,
falsePositive ? mw.msg( 'al-incorrect' ) : mw.msg( 'al-correct' )
),
minor: true,
watchlist: 'nochange',
token: mw.user.tokens.get( 'editToken' )
},
page = data.query.pages[ data.query.pageids[0] ],
isMissing = page.missing === '';
if ( note ){
note = note.replace( /\|/g, '{{!}}' );
template = falsePositive
? mw.message( 'al-problem-template-with-note', revision, note ).plain()
: mw.message( 'al-correct-template-with-note', revision, note ).plain();
} else {
template = falsePositive
? mw.message( 'al-problem-template', revision ).plain()
: mw.message( 'al-correct-template', revision ).plain();
}
if ( isMissing ){
api.get( {
list: 'abusefilters',
abfdir: 'older',
abflimit: 1,
abfprop: 'id'
} )
.done( function( data ){
var i;
text = mw.message( 'al-page-header' ).plain();
for( i = 1; i <= filter; i++ ){
text += '\n== ' + mw.msg( 'al-section-title', i ) + ' ==\n\n';
}
text += '\n' + template;
for(; i <= data.query.abusefilters[0].id; i++ ){
text += '\n== ' + mw.msg( 'al-section-title', i ) + ' ==\n\n';
}
editParams.text = text;
doEdit( editParams );
} )
.fail( function ( code, data ) {
mw.notify( mw.msg( 'al-filter-count-error', data.error.info ), {
autoHide: false,
tag: 'status'
} );
$.removeSpinner( 'af-status-spinner' );
} );
} else {
text = page.revisions[0]['*'];
text = text.replace( reTemplate, '' ) + '\n' + template;
start = text.search( /^.*\{\{[Aa]ção/m );
text = text.substr( 0, start ).replace( /\n+$/g, '\n\n' ) +
text.substr( start )
.split( '\n' )
.sort()
.join( '\n' )
.replace( /^\n+/g, '' )
// TODO: remove these temporary hacks
.replace( /(^|\n)\*\s+\{\{Ação/g, '$1*{' + '{Ação' )
.replace( /(\* *\{\{ *Ação *\| *(\d+)\D.+\n)(\* *\{\{ *Ação *\| *\2\D.+\n)+/g, '$1' );
editParams.basetimestamp = page.revisions[0].timestamp;
editParams.starttimestamp = page.revisions[0].starttimestamp;
editParams.text = text;
doEdit( editParams );
}
},
getPageContent = function (){
period = getPeriodFromTimestamp(
$( 'fieldset' ).find( 'p:first span:first' )
.contents().first()
.text()
);
if( !period ){
$( '#al-submit' ).removeAttr( 'disabled' );
return;
}
$( '#al-submit' ).injectSpinner( 'af-status-spinner' );
$( '#mw-content-text' ).find( 'fieldset p > span > a' ).each( function(){
filter = $( this ).attr( 'href' ).match( /Especial:Filtro_de_abusos\/(\d+)$/ );
if( filter && filter[1] ){
filter = filter[1];
return false;
}
} );
api.get( {
prop: 'info|revisions',
rvprop: 'content|timestamp',
intoken: 'edit',
rvsection: filter,
rvlimit: 1,
indexpageids: true,
titles: mw.msg( 'al-page-title', period )
} )
.done( defineStatus )
.fail( function ( code, data ) {
if ( code === 'rvnosuchsection' ){
mw.notify( mw.msg( 'al-page-content-error', data.error.info ), {
autoHide: false,
tag: 'status'
} );
}
$.removeSpinner( 'af-status-spinner' );
} );
};
$( '#al-submit' ).attr( 'disabled', 'disabled' );
note = $( '#al-note' ).val();
mw.loader.using( [
'mediawiki.api.edit',
'jquery.spinner',
'mediawiki.notify',
'mediawiki.notification'
], getPageContent );
}
function addAbuseFilterStatusLinks(){
var desc = $( 'fieldset' ).find( 'p:first span:first' )
.text().match( /Descrição do filtro: (.+?) \(/ );
reTemplate = new RegExp( mw.message( 'al-template-regex', revision ).plain(), 'g' );
$( 'fieldset h3' ).first().before(
$( '<h3>' ).text( mw.msg( 'al-header' ) ),
$( '<p>' ).text(
desc && desc[1] ?
mw.msg( 'al-specific-question', desc[1] ) :
mw.msg( 'al-question' )
)
.append(
$( '<br />' ),
$( '<input>' ).attr( {
'name': 'al-status',
'id': 'al-status-correct',
'type': 'radio',
'value': 'correct'
} ).prop( 'checked', true ),
$( '<label>' ).attr( {
'for': 'al-status-correct',
'title': mw.msg( 'al-correct-description' )
} ).text( mw.msg( 'al-yes' ) ),
$( '<input>' ).attr( {
'name': 'al-status',
'id': 'al-status-incorrect',
'type': 'radio',
'value': 'incorrect'
} ),
$( '<label>' ).attr( {
'for': 'al-status-incorrect',
'title': mw.msg( 'al-incorrect-description' )
} ).text( mw.msg( 'al-no' ) ),
' ',
$( '<input>' ).attr( {
'type': 'text',
'id': 'al-note',
'placeholder': mw.msg( 'al-placeholder' ),
'size': 50
} ),
$( '<input>' ).attr( {
'type': 'submit',
'value': mw.msg( 'al-submit' ),
'id': 'al-submit',
'title': mw.msg( 'al-submit-description' )
} ).click( onClick )
)
);
}
function markAbuseFilterEntriesByStatus( texts ){
mw.util.addCSS(
'.af-log-false-positive { background: #FDD; } ' +
'.af-log-correct { background: #DFD; }'
);
$( '#mw-content-text' ).find( 'li' ).each( function(){
var log, $currentLi = $( this );
$currentLi.find( 'a' ).each( function(){
var note, period,
match = $( this ).attr( 'href' )
.match( reDetailsPage );
if( match && match[1] ){
log = match[1];
reTemplate = new RegExp( mw.message( 'al-template-regex', log ).plain(), 'g' );
period = curLogs[ log ].timestamp.substring( 0, 4 ) + '/' +
curLogs[ log ].timestamp.substring( 5, 7 );
match = texts[ period ].match( reTemplate );
if( match ){
note = match[0].match( /nota *= *(.+?) *(?:\||\}\} *(?:\n|$))/ );
// Highlight log entries already checked
if( /\| *erro *= *sim/.test( match[0] ) ){
// add af-false-positive class
$currentLi
.addClass( 'af-log-false-positive' )
.attr(
'title',
note ? mw.msg( 'al-log-false-positive-note', mw.html.escape( note[1] ) )
: mw.msg( 'al-log-false-positive' )
);
} else {
$currentLi
.addClass( 'af-log-correct' )
.attr(
'title',
note ? mw.msg( 'al-log-correct-note', mw.html.escape( note[1] ) )
: mw.msg( 'al-log-correct' )
);
}
}
return false;
}
} );
} );
}
function getSectionsFromPages( sections ){
var // key, section,
// pages = [],
revParams = {
action: 'query',
prop: 'revisions',
rvprop: 'content'
// ,indexpageids: true
};
/*
for( key in sections ){
pages.push( mw.msg( 'al-page-title', key ) );
if( sections[ key ].length === 1 ){
// FIXME: Get only one section
} else {
// Get the whole page
}
}
*/
revParams.titles = Object.keys( sections ).join( '|' );
api.get( revParams )
.done( function( data ){
var statusTexts = {},
reAnalysisPage = new RegExp( mw.message( 'al-analysis-page-regex' ).plain() );
$.each( data.query.pages, function( id ){
var period,
pg = data.query.pages[ id ];
if ( pg.missing !== '' ){
period = pg.title.match( reAnalysisPage );
if( period && period[1] ){
statusTexts[ period[1] ] = pg.revisions[0]['*'];
}
}
} );
markAbuseFilterEntriesByStatus( statusTexts );
} );
}
function getPagesToCheck(){
var d,
query = mw.Uri().query,
// The log with the provided offset is returned
// by the API but not by the special page
// Adding +1 or -1 ensures the last item from the
// special page is also returned by the API
offset = query.dir === 'prev' ? 1 : -1,
abuseLogParams = {
action: 'query',
list: 'abuselog',
aflprop: 'ids|timestamp',
afldir: query.dir === 'prev' ? 'newer' : 'older',
afllimit: query.limit || 50
};
if( query.wpSearchUser ){
abuseLogParams.afluser = query.wpSearchUser;
}
if( query.wpSearchTitle ){
abuseLogParams.afltitle = query.wpSearchTitle;
}
if( query.wpSearchFilter ){
abuseLogParams.aflfilter = query.wpSearchFilter;
}
// FIXME: Is this correct? Are the other values of 'dir'?
if( query.offset ){
d = query.offset;
d = new Date( Date.UTC(
d.substring( 0, 4 ),
d.substring( 4, 6 ) - 1,
d.substring( 6, 8 ),
d.substring( 8, 10 ),
d.substring( 10, 12 ),
// The special page returns logs whose timestamp < T (not <= T)
parseInt( d.substring( 12, 14 ), 10 ) + offset
) ).toISOString();
abuseLogParams.aflstart = d;
}
api.get( abuseLogParams )
.done( function( data ){
var i, log, filter, period, page,
sections = {};
// FIXME: Sort the logs (mainly if query.dir === 'prev')
for( i = 0; i < data.query.abuselog.length; i++ ) {
log = data.query.abuselog[i];
curLogs[ log.id ] = {
filter: log.filter_id,
timestamp: log.timestamp
};
// YYYY/MM
period = log.timestamp.substring( 0, 4 ) + '/' +
log.timestamp.substring( 5, 7 );
filter = log.filter_id;
page = mw.msg( 'al-page-title', period );
if( sections[ page ] ){
sections[ page ].push( filter );
} else {
sections[ page ] = [];
}
}
getSectionsFromPages( sections );
} );
}
if ( mw.config.get( 'wgCanonicalSpecialPageName' ) === 'AbuseLog'
&& mw.config.get( 'wgDBname' ) === 'ptwiki'
) {
reDetailsPage = /Especial:Registro_de_abusos\/(\d+)$/;
reFilterLink = /^\/wiki\/Especial:Filtro_de_abusos\/(\d+)$/;
mw.loader.using( [ 'mediawiki.api', 'mediawiki.Uri' ], function(){
api = new mw.Api();
if ( mw.config.get( 'wgTitle' ) === 'Registro de abusos' ){
$( getPagesToCheck );
} else {
revision = mw.config.get( 'wgPageName' ).match( reDetailsPage );
if( revision && revision[1] ){
revision = revision[1];
$( addAbuseFilterStatusLinks );
}
}
} );
}
}( mediaWiki, jQuery ) );All content in the above text box is licensed under the Creative Commons Attribution-ShareAlike license Version 4 and was originally sourced from https://pt.wikibooks.org/w/index.php?diff=prev&oldid=263297.
![]() ![]() This site is not affiliated with or endorsed in any way by the Wikimedia Foundation or any of its affiliates. In fact, we fucking despise them.
|