![]() | Approved 2009-04-08 Wikipedia:Bots/Requests for approval/AnomieBOT 28 |
package tasks::WikiProjectWorker;
=pod
=begin metadata
Task: WikiProjectWorker
BRFA: Wikipedia:Bots/Requests for approval/AnomieBOT 28
Status: Approved 2009-04-08
Rate: Max 6 edits/minute
Created: 2009-03-27
OnDemand: true
Perform various tasks at the request of the affected WikiProjects:
* Add or remove banners on a specific set of pages (e.g. pages in a category, pages transcluding a template).
* Adjust banner parameters, particularly assessments and task forces.
* Fix banner shells on pages edited for the above reasons.
=end metadata
=cut
use utf8;
use strict;
use Data::Dumper;
use Digest::SHA qw/sha256_base64/;
use AnomieBOT::Task;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;
### Request link, for edit summary.
my $req="[[User:AnomieBOT/req/WPVG 1|request]]";
### Increment this number every time a new run is started, so we don't have to
### mess around with deleting previous runs' database entries.
my $seq=2;
### How to find the pages?
my %templates=('MortalKombatProject' => 'MortalKombat', 'Wikiproject Pro Gaming' => 'Progaming');
my @iterators=(
{
list => 'embeddedin',
eititle => [ map "Template:$_", keys %templates ],
eilimit => 'max',
},
);
### Filter function: manipulate the found data as necessary, returning the talk
### page to tag (or undef to skip).
sub filter {
return $_[0]->{'title'};
}
# Banner configurations.
my %banner_cfgs=(
'WikiProject Video games' => {
meta => 0,
stubauto => undef,
canonicalize => 'WikiProject Video games',
},
);
sub new {
my $class=shift;
my $self=$class->SUPER::new();
$self->{'config loaded'}=0;
bless $self, $class;
return $self;
}
=pod
=for info
Approved 2009-04-08<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 28]]
=cut
sub approved {
return -1;
}
sub run {
my ($self, $api)=@_;
my $res;
$api->task('WikiProjectWorker', 0, 10, qw/d::Util d::WikiProjectTagging/);
my $errto = 'Errors? [[User:'.$api->user.'/shutoff/WikiProjectWorker]]';
# Load configs, if necessary
if(!$self->{'config loaded'}){
my %cfg=();
while(my ($banner,$cfg)=each %banner_cfgs){
$cfg=$api->WPBMetaConfig($cfg->{'meta'}, %$cfg) if exists($cfg->{'meta'});
$cfg{$banner}=$cfg;
}
$api->WPBconfig(%cfg);
$self->{'config loaded'}=1;
}
if(($api->store->{'configured'} // 0) < $seq){
### Initialize configuration here
#$api->store->{'conflicting assessments'}='';
#$api->store->{'NA assessments'}='';
}
### Update log page
#if($api->store->{'conflicting assessments'} ne '' || $api->store->{'NA assessments'} ne ''){
# my $tok=$api->edittoken('Wikipedia:WikiProject Japan/Assessment/Tag cleanup');
# if($tok->{'code'} ne 'success'){
# $api->warn("Cannot update log: ".$tok->{'error'}."\n");
# return 60;
# }
# my $txt=$tok->{'revisions'}[0]{'*'};
# my $a=$api->store->{'conflicting assessments'};
# my $b=$api->store->{'NA assessments'};
# unless($txt=~s/(<!-- Insert conflicting assessments above here -->)/$a$1/ &&
# $txt=~s/(<!-- Insert NA assessments above here -->)/$b$1/){
# $api->warn("Log is missing conflicting assessments marker");
# $api->whine("[[Wikipedia:WikiProject Japan/Assessment/Tag cleanup]] is broken", "Help! [[Wikipedia:WikiProject Japan/Assessment/Tag cleanup]] is missing the comments that tell me where to insert new log entries. I can't do anything to that page until someone fixes it.");
# return 60;
# }
# $api->warn("Updating log\n");
# my $r=$api->edit($tok, $txt, "Bot updating log", 0, 0);
# if($r->{'code'} ne 'success'){
# $api->warn("Write failed on log: ".$r->{'error'}."\n");
# return 60;
# }
# $api->store->{'conflicting assessments'}='';
# $api->store->{'NA assessments'}='';
#}
# Preload cache
$api->redirects_to(map "Template:$_", keys %templates);
# Spend a max of 5 minutes on this task before restarting
my $endtime=time()+300;
foreach my $itercfg (@iterators) {
my $iter=$api->iterator(%$itercfg);
while(my $page=$iter->next()){
if(!$page->{'_ok_'}){
$api->warn("Could not retrieve page from iterator: ".$page->{'error'}."\n");
return 60;
}
my $pageid=$page->{'pageid'};
next if ($api->store->{$pageid} // 0) >= $seq;
my $title=filter($page);
if(!defined($title)){
$api->warn("Skipping ".$page->{'title'}.", filter returned undef\n");
$api->store->{$pageid}=$seq;
next;
}
my $tok=$api->edittoken($title, EditRedir => 1);
if($tok->{'code'} eq 'shutoff'){
$api->warn("Task disabled: ".$tok->{'content'}."\n");
return 300;
}
if($tok->{'code'} ne 'success'){
$api->warn("Failed to get edit token for $title: ".$tok->{'error'}."\n");
next;
}
if(($tok->{'ns'}&1)==0){
$api->warn("Cannot edit $title: namespace ".$tok->{'ns'}." is non-talk\n");
$api->store->{$pageid}=$seq;
next;
}
if(exists($tok->{'redirect'})){
$api->warn("$title is a redirect, skipping.\n");
$api->store->{$pageid}=$seq;
next;
}
$api->warn("Checking $title...\n");
my $intxt=exists($tok->{'revisions'}[0]{'*'})?$tok->{'revisions'}[0]{'*'}:'';
my ($outtxt,$nowiki)=$api->strip_nowiki($intxt);
### PROCESSING ###
# Is there a WikiProject Japan template already on the page?
my $need_WPVG=($api->WPBcheck($outtxt, "WikiProject Video games") == 0);
# First, remove the to-be-removed templates and calculate task
# force parameters.
my $fail=0;
my $class=undef;
my $imp=undef;
my %tf=();
my %found=();
(undef,$outtxt)=$api->WPBcheck($outtxt, sub {
my $banner=shift;
my $name=shift;
my $oname=shift;
my @params=@{shift()};
$tf{$templates{$banner}}=1;
$found{"{{$name}}"}=$templates{$banner}.'=yes';
foreach (@params) {
if(/^\s*class\s*=\s*(\S.*?)\s*$/s){
$fail=1 if(defined($class) && lc($class) ne lc($1));
$class=$1;
}
if(/^\s*importance\s*=\s*(\S.*?)\s*$/s){
$fail=1 if(defined($imp) && lc($imp) ne lc($1));
$imp=$1;
}
}
return '' unless $need_WPVG;
$need_WPVG=0;
return '{{WikiProject Video games}}';
}, keys %templates);
if(ref($outtxt) eq 'HASH'){
$api->warn("Processing $title failed: ".$outtxt->{'error'}."\n");
next;
}
# Second, add (or replace) {{WikiProject Video games}}
my @tf=map "$_=yes", keys %tf;
my @assess=();
if($fail){
warn "Conflicting assessments on $title\n";
#$api->store->{'conflicting assessments'}.="* [[:$title]]\n";
} else {
push @assess, "class=$class" if defined($class);
push @assess, "importance=$imp" if defined($imp);
#$api->store->{'NA assessments'}.="* [[:$title]]\n" if ($class // '') eq 'na';
}
my $assess=undef;
unless(defined($class)){
$assess=$api->WPBassess($title);
if(ref($assess) eq 'HASH'){
if($assess->{'code'} eq 'pagemissing'){
# No subject page, doesn't matter
$assess=undef;
} else {
$api->warn("Processing $title failed: ".$assess->{'error'}."\n");
next;
}
}
}
$outtxt=$api->WPBadd($outtxt, $assess, sub {
shift; # $banner
shift; # $name
my $oname=shift;
my $params=shift;
shift; # $wikitext
my $new=shift;
return undef if $new;
foreach my $tf (keys %tf) {
push @$params, "$tf=yes" unless(grep(s/^(\s*\Q$tf\E\s*=(?:\s*(?=\S))?).*?(\s*)$/${1}yes$2/s, @$params));
}
if(@assess){
if(defined($class)){
unless(grep(/^\s*class\s*=\s*\S/, @$params)){
push @$params, "class=$class" unless(grep(s/^(\s*class\s*=)(\s*)$/$1$class$2/s, @$params));
}
}
if(defined($imp)){
unless(grep(/^\s*importance\s*=\s*\S/, @$params)){
push @$params, "importance=$imp" unless(grep(s/^(\s*importance\s*=)(\s*)$/$1$imp$2/s, @$params));
}
}
}
return "{{$oname}}" unless @$params;
return "{{$oname|".join("|", @$params)."}}";
}, 'WikiProject Video games', @tf, @assess);
if(ref($outtxt) eq 'HASH'){
$api->warn("Processing $title failed: ".$outtxt->{'error'}."\n");
next;
}
$outtxt=$api->replace_nowiki($outtxt, $nowiki);
# Need to edit?
if($outtxt ne $intxt){
$outtxt=$api->WPBfixshell($outtxt);
if(ref($outtxt) eq 'HASH'){
$api->warn("Processing $title failed: ".$outtxt->{'error'}."\n");
next;
}
my @found=keys %found;
$found[-1]='and '.$found[-1] if @found>1;
my $summary="Replacing ".join((@found>2)?', ':' ', @found)." with {{WikiProject Video games|".join('|', values %found)."}} per $req $errto";
$api->warn("$summary in $title\n");
my $r=$api->edit($tok, $outtxt, $summary, 1, 1);
if($r->{'code'} ne 'success'){
$api->warn("Write failed on $title: ".$r->{'error'}."\n");
next;
}
} else {
$api->warn("Nothing to do in $title\n");
}
# Remember that we processed this page already
$api->store->{$pageid}=$seq;
# If we've been at it long enough, let another task have a go.
return 0 if time()>=$endtime;
}
}
# No more pages to check, try again in 10 minutes or so in case of errors.
return 600;
}