User:AnomieBOT/source/tasks/SafesubstFixer.pm

From Wikipedia, the free encyclopedia
package tasks::SafesubstFixer;

=pod

=begin metadata

Bot:     AnomieBOT
Task:    SafesubstFixer
BRFA:    Wikipedia:Bots/Requests for approval/AnomieBOT 37
Status:  Approved 2010-05-05
Created: 2010-04-20
OnDemand: true

Replace <code><nowiki>{{{subst|}}}</nowiki></code> in specifically named templates with <code><nowiki><includeonly>safesubst:</includeonly></nowiki></code>. If appropriate, may also insert <code><nowiki><includeonly>safesubst:</includeonly></nowiki></code> into <code><nowiki>{{#if</nowiki></code> and other parser functions, or specifically named template invocations.

=end metadata

=cut

use utf8;
use strict;

use AnomieBOT::Task;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;

sub new {
    my $class=shift;
    my $self=$class->SUPER::new();
    bless $self, $class;
    return $self;
}

=pod

=for info
BRFA approved 2010-05-05<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 37]]

=cut

sub approved {
    return -1;
}

sub run {
    my ($self, $api)=@_;
    my $res;

    $api->task('SafesubstFixer', 0, 10, qw/d::Nowiki/);

    # Spend a max of 5 minutes on this task before restarting
    my $endtime=time()+300;

    # Replacements
    my @re=(
        qr/\{\{\{subst\|\}\}\}/, '<includeonly>safesubst:</includeonly>',
        qr/\{\{#if/, '{{<includeonly>safesubst:</includeonly>#if',
        qr/\{\{#switch/, '{{<includeonly>safesubst:</includeonly>#switch',
    );
    my $summary="Replacing {{{subst|}}} with <includeonly>safesubst:</includeonly> (and inserting it into parser function calls) per [[Wikipedia talk:Template messages/User talk namespace#safesubst:|request]]";

    my $iter=$api->iterator(
        generator    => 'allpages',
        gapprefix    => 'Uw-',
        gapnamespace => 10,
        gaplimit     => 'max',
        prop         => 'info'
    );
    while($_=$iter->next){
        return 0 if $api->halting;

        if(!$_->{'_ok_'}){
            $api->warn("Failed to retrieve page list: ".$_->{'error'}."\n");
            return 60;
        }

        my $title=$_->{'title'};

        # WTF?
        if(exists($_->{'missing'})){
            $api->warn("$title is missing? WTF?\n");
            next;
        }

        next if exists($api->store->{$_->{'pageid'}});

        # Ok, check the page
        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;
        }
        next if exists($tok->{'missing'});

        # Get page text
        my $intxt=$tok->{'revisions'}[0]{'slots'}{'main'}{'*'};

        # Perform the replacements
        my ($outtxt,$nowiki)=$api->strip_nowiki($intxt);
        for(my $i=0; $i<@re; $i+=2){
            my $search=$re[$i];
            my $repl=$re[$i+1];
            $outtxt=~s/$search/$repl/g;
        }
        $outtxt=~s!<includeonly>(.*?)</includeonly>! fix_nested_noinclude($1) !ge;
        $outtxt=$api->replace_nowiki($outtxt, $nowiki);

        # Need to edit?
        if($outtxt ne $intxt){
            $api->log("$summary in $title");
            my $r=$api->edit($tok, $outtxt, $summary, 1, 1);
            if($r->{'code'} ne 'success'){
                $api->warn("Write failed on $title: ".$r->{'error'}."\n");
                next;
            }
            $api->store->{$_->{'pageid'}}=1;
        }

        # If we've been at it long enough, let another task have a go.
        return 0 if time()>=$endtime;
    }

    # No more pages to check
    return undef;
}

sub fix_nested_noinclude {
    my $x=shift;
    return $x=~/(.*)<includeonly>safesubst:/ ? "<includeonly>${1}safesubst:</includeonly><includeonly>" : "<includeonly>$x</includeonly>";
}

1;