User:AnomieBOT/source/tasks/TemplateSubster.pm
Appearance
Approved 2010-10-06 Wikipedia:Bots/Requests for approval/AnomieBOT 45 |
package tasks::TemplateSubster;
=pod
=begin metadata
Bot: AnomieBOT
Task: TemplateSubster
BRFA: Wikipedia:Bots/Requests for approval/AnomieBOT 45
Status: Approved 2010-10-06
Created: 2010-09-27
Subst templates in [[:Category:Wikipedia templates to be automatically substituted]].
See [[User:AnomieBOT/docs/TemplateSubster|documentation]] for details.
=end metadata
=cut
use utf8;
use strict;
use Data::Dumper;
use AnomieBOT::Task qw/:time/;
use tasks::TemplateSubster::Base;
use Time::HiRes;
use vars qw/@ISA/;
@ISA=qw/tasks::TemplateSubster::Base/;
sub new {
my $class=shift;
my $self=$class->SUPER::new();
bless $self, $class;
return $self;
}
=pod
=for info
Approved 2010-10-06<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 45]]
=cut
sub approved {
return 3;
}
sub run {
my ($self, $api)=@_;
my $res;
$api->task('TemplateSubster',0,10,qw/d::Redirects d::Templates d::Talk d::IWNS/);
$res = $self->fetchSig( $api );
return $res if defined( $res );
# Fetch max transclusions limit
$res=$api->query(titles=>'User:'.$api->user.'/TemplateSubster max transclusions', prop=>'info|revisions', rvlimit=>1, rvprop=>'content', rvslots=>'main', inprop=>'protection');
if($res->{'code'} ne 'success'){
$api->warn("Failed to get max transclusions limit: ".$res->{'error'}."\n");
return 60;
}
$res=(values %{$res->{'query'}{'pages'}})[0];
my $max_transclusions = 5;
if(!exists($res->{'missing'})){
my $ok=0;
foreach (@{$res->{'protection'}}) {
$ok=1 if($_->{'type'} eq 'edit' && $_->{'level'} eq 'sysop');
}
if(!$ok){
$api->whine("[[User:".$api->user."/TemplateSubster max transclusions]] is unprotected", "In an effort to prevent disruption, I refuse to subst templates that have over a certain number of transclusions unless they are listed at [[User:".$api->user."/TemplateSubster force]]. But it defeats the purpose if the page defining that number is not fully protected. Please have that page protected.");
return 300;
}
$max_transclusions = $res->{'revisions'}[0]{'slots'}{'main'}{'*'};
$max_transclusions =~ s/^\s*|\s*$//sg;
unless($max_transclusions =~ /^\d+$/){
$api->whine("[[User:".$api->user."/TemplateSubster max transclusions]] is invalid", "The page must contain a single positive integer. No comments, transclusions, or other text. Please fix.");
return 300;
}
}
$res=$api->query(titles=>'User:'.$api->user.'/TemplateSubster force', prop=>'info|links', pllimit=>'max', inprop=>'protection');
if($res->{'code'} ne 'success'){
$api->warn("Failed to get force list: ".$res->{'error'}."\n");
return 60;
}
$res=(values %{$res->{'query'}{'pages'}})[0];
my %force = ();
if(!exists($res->{'missing'})){
my $ok=0;
foreach (@{$res->{'protection'}}) {
$ok=1 if($_->{'type'} eq 'edit' && ($_->{'level'} eq 'sysop' || $_->{'level'} eq 'templateeditor'));
}
if($ok){
foreach (@{$res->{'links'}}) {
$force{$_->{'title'}} = 1;
}
} else {
$api->whine("[[User:".$api->user."/TemplateSubster force]] is unprotected", "In an effort to prevent disruption, I refuse to subst templates that have over $max_transclusions transclusions unless they are listed at [[User:".$api->user."/TemplateSubster force]]. But it defeats the purpose if that page is not fully protected or template-protected. Please have that page protected.");
}
}
my %rns = $api->namespace_reverse_map();
# Spend a max of 5 minutes on this task before restarting
my $endtime=time()+300;
# API doesn't have an efficient query, so use the DB
my ($dbh);
eval {
($dbh) = $api->connectToReplica( 'enwiki' );
};
if ( $@ ) {
$api->warn( "Error connecting to replica: $@\n" );
return 300;
}
my @rows;
my $t0 = Time::HiRes::time();
eval {
@rows = @{ $dbh->selectall_arrayref( qq{
SELECT page_namespace, page_title, COUNT(distinct tl_from) AS ct
FROM categorylinks JOIN page ON(cl_from=page_id) LEFT JOIN linktarget ON(lt_namespace=page_namespace AND lt_title=page_title) LEFT JOIN templatelinks ON(tl_target_id=lt_id)
WHERE cl_to='Wikipedia_templates_to_be_automatically_substituted'
GROUP BY page_namespace, page_title
}, { Slice => {} } ) };
};
if ( $@ ) {
$api->warn( "Error fetching page list from replica: $@\n" );
return 300;
}
my $t1 = Time::HiRes::time();
$api->log( 'DB query took ' . ($t1-$t0) . ' seconds' );
return 3600 unless @rows;
my %process = ();
my @tmpl = ();
for my $row (@rows) {
utf8::decode( $row->{'page_title'} ); # Data from database is binary
my $title = $row->{'page_title'};
$title = $rns{$row->{'page_namespace'}} . ':' . $title if $row->{'page_namespace'} != 0;
$title =~ s/_/ /g;
if($row->{'ct'} > $max_transclusions && !($force{$title} // 0)){
my $iter = $api->iterator(
list => 'recentchanges',
rcprop => 'timestamp|ids|user|comment',
rctype => 'categorize',
rctitle => 'Category:Wikipedia templates to be automatically substituted',
rclimit => 'max',
);
my $who = '';
my $who2 = '';
while ( my $rc = $iter->next ) {
if ( !$rc->{'_ok_'} ) {
$api->warn( "Failed to retrieve recent changes: " . $rc->{'error'} . "\n" );
return 60;
}
if ( !exists($rc->{'commenthidden'}) && !exists($rc->{'userhidden'}) && $rc->{'comment'} =~ /^\[\[:\Q$title\E\]\] added to category/ ) {
$who = ' <small>Possibly added by [[User:' . $rc->{'user'} . ']] at [[Special:Diff/' . $rc->{'revid'} . '|' . $rc->{'timestamp'} . ']].</small>';
$who2 = '; possibly added by [[User:' . $rc->{'user'} . ']] in [[Special:Diff/' . $rc->{'revid'} . ']] at ' . $rc->{'timestamp'};
last;
}
}
$api->log("Skipping $title, $row->{ct} transclusions > max $max_transclusions" . $who2);
$api->whine("[[$title]] has too many transclusions", "{{N.b.}} <b>Note that TFD substitutions should now be done via [[User:AnomieBOT/TFDTemplateSubster]] rather than by (ab)using TemplateSubster!</b>\n\nIn an effort to prevent disruption, I refuse to subst templates that have over $max_transclusions transclusions unless they are listed at [[User:".$api->user."/TemplateSubster force]]. Please either edit the template to remove it from [[:Category:Wikipedia templates to be automatically substituted]], manually subst the [{{fullurl:Special:WhatLinksHere/$title|hidelinks=1&hideredirs=1}} existing transclusions], or add it to [[User:".$api->user."/TemplateSubster force]] to let me know it is OK to subst them.$who");
} else {
push @tmpl, $title;
$process{$title} = 0 if $row->{'ct'} > 0;
}
}
return 3600 unless %process; # Nothing to process
# Don't resolve in case only a redirect should be substed for some strange reason.
my %r=$api->redirects_to(@tmpl);
if(exists($r{''})){
$api->warn("Failed to get redirects: ".$r{''}{'error'}."\n");
return 60;
}
return $self->process( $api, \%process, \%r, $endtime );
}
sub summary {
my ($self, $api, @remv) = @_;
my $help="User:".$api->user."/docs/TemplateSubster";
@remv = map { "{{$_}}" } @remv;
$remv[-1] = 'and ' . $remv[-1] if @remv > 1;
return "[[$help|Substing templates]]: " . join( ( @remv > 2 ) ? ', ' : ' ', @remv ) . ". See [[$help]] for info.";
}
1;