![]() | Approved 2009-07-09 Wikipedia:Bots/Requests for approval/AnomieBOT 31 |
![]() | Supplemental BRFA approved 2024-02-04 Wikipedia:Bots/Requests for approval/AnomieBOT 82 |
package tasks::TalkTemplateMover;
=pod
=begin metadata
Bot: AnomieBOT
Task: TalkTemplateMover
BRFA: Wikipedia:Bots/Requests for approval/AnomieBOT 31
Status: Approved 2009-07-09
+BRFA: Wikipedia:Bots/Requests for approval/AnomieBOT 82
+Status: Approved 2024-02-04
Created: 2009-06-18
Find transclusions of {{tl|translated page}} and other templates documented for talk pages
mistakenly placed on article pages, and move them to the corresponding talk page.
=end metadata
=cut
use utf8;
use strict;
use AnomieBOT::Task;
use Data::Dumper;
use Digest::SHA qw/sha256_base64/;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;
my $did_redir=0;
my %templates=(
'Template:Translated page' => 1,
'Template:Interwiki copy' => 1,
);
my @skip_templates=(
'Template:Archive box',
'Template:Archives',
);
sub new {
my $class=shift;
my $self=$class->SUPER::new();
$self->{'order'}=100;
bless $self, $class;
return $self;
}
=pod
=for info
Approved 2009-07-09<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 31]]
=for info
Supplemental BRFA approved 2024-02-04<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 82]]
=cut
sub approved {
return 3;
}
sub run {
my ($self, $api)=@_;
my $res;
$api->task('TalkTemplateMover', 0, 10, qw/d::Talk d::Templates d::Redirects d::Trial/);
my $screwup=' If this bot is making errors, please report it at [[User:'.$api->user.'/shutoff/TalkTemplateMover]]';
if(!$did_redir){
my %r=$api->redirects_to_resolved(keys %templates);
if(exists($r{''})){
$api->warn("Failed to get template redirects: ".$r{''}{'error'}."\n");
return 60;
}
%templates=%r;
my %skip=$api->redirects_to_resolved(@skip_templates);
if(exists($skip{''})){
$api->warn("Could not load list of redirects for skip templates: ".$skip{''}{'error'}."\n");
return undef;
}
@skip_templates=keys %skip;
$did_redir=1;
}
my $iter=$api->iterator(
generator => 'embeddedin',
geititle => [ keys %templates ],
geinamespace => 0,
geilimit => '1000',
prop => 'revisions',
rvprop => 'content',
rvslots => 'main',
);
while($_=$iter->next){
return 0 if $api->halting;
if(!$_->{'_ok_'}){
$api->warn("Failed to retrieve transclusion list: ".$_->{'error'}."\n");
return 60;
}
my $title=$_->{'title'};
my $intxt=$_->{'revisions'}[0]{'slots'}{'main'}{'*'};
my %tmpl=();
my @moved=();
my $outtxt=$api->process_templates($intxt, sub {
my $name=shift;
my $params=shift;
my $wikitext=shift;
shift; # $data
shift; # $oname
return undef unless exists($templates{"Template:$name"});
$tmpl{key($api,$name,$params)}=$wikitext;
push @moved, "{{$name}}";
return '';
});
next if $intxt eq $outtxt;
$moved[-1]='and '.$moved[-1] if @moved>1;
my $moved=join((@moved>2)?', ':' ', @moved);
my $tl_moved=$moved; $tl_moved=~s/\{\{/{{tl|/g;
$api->log("Moving $moved from $title to Talk:$title");
my $tok1=$api->edittoken($title, EditRedirect => 1);
if($tok1->{'code'} eq 'shutoff'){
$api->warn("Task disabled: ".$tok1->{'content'}."\n");
return 300;
}
if($tok1->{'code'} eq 'pageprotected'){
$tok1=undef;
} elsif($tok1->{'code'} ne 'success'){
$api->warn("Failed to get edit token for $title: ".$tok1->{'error'}."\n");
return 60;
} elsif($tok1->{'revisions'}[0]{'slots'}{'main'}{'*'} ne $intxt){
$api->log("Page changed while processing! Skip for now.");
next;
}
my $tok2=$api->edittoken("Talk:$title", EditRedirect => 1);
if($tok2->{'code'} eq 'shutoff'){
$api->warn("Task disabled: ".$tok2->{'content'}."\n");
return 300;
}
if($tok2->{'code'} ne 'success'){
$api->warn("Failed to get edit token for Talk:$title: ".$tok2->{'error'}."\n");
return 60;
}
if(exists($tok2->{'redirect'})){
$api->warn("Talk:$title is a redirect, cannot move $moved\n");
$api->whine("[[:$title]] cannot be processed", "The talk page [[Talk:$title]] is a redirect, so I am unwilling to move $tl_moved. Please handle it manually.");
next;
}
my $intalk=$tok2->{'revisions'}[0]{'slots'}{'main'}{'*'} // '';
my $outtalk=$api->process_templates($intalk, sub {
my $name=shift;
my $params=shift;
my $wikitext=shift;
shift; # $data
shift; # $oname
return undef unless exists($templates{"Template:$name"});
my $k=key($api,$name,$params);
delete $tmpl{$k} if exists($tmpl{$k});
return undef;
});
$outtalk=$self->tag($api, $outtalk, join("\n", values %tmpl)) if %tmpl;
my $summary="Moving $moved from [[:$title]] per that template's documentation";
if(!defined($tok1)){
$outtalk=~s/\s+$//;
my $rq;
if(@moved==1){
$rq="== Editprotected request ==\n{{editprotected}} The template $tl_moved belongs on this talk page rather than on the article itself, but I cannot remove it as this page is fully protected. Please remove it for me. Thanks.";
} else {
$rq="== Editprotected request ==\n{{editprotected}} The templates $tl_moved belong on this talk page rather than on the article itself, but I cannot remove them as this page is fully protected. Please remove them for me. Thanks.";
}
if(index($outtalk,$rq)<0){
$outtalk.="\n\n$rq ~~~~\n";
$summary.=" (and adding an {{editprotected}})";
}
}
if($intalk ne $outtalk){
my $res=$api->edit($tok2, $outtalk, "$summary. $screwup", 0, defined($tok1)?1:0);
if($res->{'code'} ne 'success'){
$api->warn("Write failed on Talk:$title: $res->{error}\n");
return 60;
}
} else {
$api->log("No edit to Talk:$title necessary");
}
if(defined($tok1)){
my $res=$api->edit($tok1, $outtxt, "Moving $moved to [[Talk:$title]] per that template's documentation. $screwup", 0, 1);
if($res->{'code'} ne 'success'){
$api->warn("Write failed on $title: $res->{error}\n");
return 60;
}
}
}
return 3600;
}
sub key {
my $api=shift;
my $name=shift;
my $params=shift;
my $k=$templates{"Template:$name"};
foreach ($api->process_paramlist(@$params)){
$_->{'name'}=~s/^\s+|\s+$//g;
$_->{'value'}=~s/^\s+|\s+$//g;
$k.='|'.$_->{'name'}.'='.$_->{'value'};
}
return $k;
}
sub tag {
my $self=shift;
my $api=shift;
my $txt=shift;
my $tmpl=shift;
my $nowiki;
($txt,$nowiki)=$api->strip_nowiki($txt);
my $outtmpl={};
$txt=$api->process_templates($txt, \&_strip_templates, $outtmpl);
$txt="$tmpl\n$txt" unless $txt=~s/^((?:\s*\x02[a-zA-Z0-9_-]+\x03)*[ \t]*)(?:$|(?=\n))/$1\n$tmpl/;
$txt=_unstrip_templates($txt, $outtmpl);
return $api->replace_nowiki($txt, $nowiki);
}
sub _strip_templates {
my ($name, $params, $wikitext, $data) = @_;
return undef if $name=~/^#/;
return undef if grep(/^\s*small\s*=\s*(?!no|n|0)\S/, @$params);
return undef if grep("Template:$name" eq $_, @skip_templates);
$wikitext=_unstrip_templates($wikitext,$data);
my $tmp = $wikitext;
utf8::encode( $tmp ) if utf8::is_utf8( $tmp );
my $tag="\x02".sha256_base64($tmp)."\x03";
$tag=~tr!+/=!-_!d;
$data->{$tag}=$wikitext;
return $tag;
}
sub _unstrip_templates {
my $wikitext=shift;
my $templ=shift;
$wikitext=~s!(\x02[a-zA-Z0-9_-]+\x03)! $templ->{$1} // $1 !gioe;
return $wikitext;
}
1;