User:AnomieBOT/source/tasks/ShowByDateSubster.pm

package tasks::ShowByDateSubster;

=pod

=begin metadata

Bot:      AnomieBOT
Task:     ShowByDateSubster
BRFA:     Wikipedia:Bots/Requests for approval/AnomieBOT 61
Status:   Approved 2012-03-21
Created:  2012-03-08

Replace expired instances of {{tl|show by date}} with the "after" text. Should an instance need to be not substed, use {{para|nosubst|yes}} or {{para|demo|yes}}.

=end metadata

=cut

use utf8;
use strict;

use Data::Dumper;
use AnomieBOT::Task qw/onlylist timegm/;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;

# List of pages to skip
my %skip=(
    'Template:Show by date' => 1,
    'Template:Show by date/doc' => 1,
    'Template:Show by date/testcases' => 1,
    'Template:Show by date/sandbox' => 1,
);

# List the rev_id of each template in %repl. If the template on-wiki doesn't
# match, the bot will not touch the template. This prevents it from making the
# wrong replacement if someone changes the template code.
my %goodrevisions=(
    'Template:Show by date' => 1252081713,
);

# Replacement functions: return the page to check if it exists and the
# replacement wikitext.
my %repl=(
    'Template:Show by date' => sub {
        my %p=%{$_[0]};
        my $t=time;
        my @t=gmtime $t;
        my $y=$p{'1'} // ''; $y=($t[5]+1900) if $y eq '';
        my $m=$p{'2'} // ''; $m=($t[4]+1) if $m eq '';
        my $d=$p{'3'} // ''; $d=$t[3] if $d eq '';
        my $h=$p{'hour'} // ''; $h=0 if $h eq '';
        my $d2=$p{'delay'} // 0; $d2=0 if $d2 eq '';
        return undef unless "$y-$m-$d-$d2-$h"=~/^\d+-\d+-\d+-\d+-\d+$/;
        my $tt=timegm(0,0,$h,$d+$d2,$m-1,$y-1900);
        return undef if $tt>$t;
        return $p{'5'}//'';
    },
);

# Iterator definitions
my @iterators=(
    {
        list    => 'embeddedin',
        eititle => ['Template:Show by date'],
        eilimit => '100',
    },
);

sub new {
    my $class=shift;
    my $self=$class->SUPER::new();
    $self->{'iter'}=undef;
    $self->{'iterators'}=[@iterators];
    bless $self, $class;
    return $self;
}

=pod

=for info
Approved 2012-03-21<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 61]]

=cut

sub approved {
    return 3;
}

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

    $api->task('ShowByDateSubster',0,10,qw/d::Redirects d::Templates d::Talk/);

    # Check if the templates are still known-good versions
    $res=$api->query(titles=>join('|',keys %goodrevisions), prop=>'info');
    if($res->{'code'} ne 'success'){
        $api->warn("Failed to check template revisions: ".$res->{'error'}."\n");
        return 60;
    }
    my %r=map { $_->{'title'},$_ } values %{$res->{'query'}{'pages'}};
    while(my ($k,$v)=each %repl){
        next if(defined($r{$k}) && !defined($goodrevisions{$k}));
        next if(defined($r{$k}) && $r{$k}{'lastrevid'}==$goodrevisions{$k});
        my $r=$api->whine("[[$k]] was modified!", "The template [[$k]] was modified from the last known good version ({{diff|page=$k|diff=cur|oldid=".$goodrevisions{$k}."|label=diff}}). Please check that my replacement function for that template is still correct, and then update the good revision id to the current revision.");
        if($r->{'code'} ne 'success'){
            $api->warn("Whine failed: ".$r->{'error'}."\n");
            return 60;
        }
        delete $repl{$k};
    }

    return undef unless %repl;

    # Get a list of templates redirecting to our targets
    my %templates=$api->redirects_to_resolved(keys %repl);
    if(exists($templates{''})){
        $api->warn("Failed to get redirects to target templates: ".$templates{''}{'error'}."\n");
        return 60;
    }
    my ($k,$v);
    $templates{$k}=$repl{$v} while(($k,$v)=each %templates);

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

    while(1){
        my $iter=$self->{'iter'};
        if(!defined($iter)){
            my $i=shift @{$self->{'iterators'}};
            last unless $i;
            $iter=$api->iterator(%$i);
            $self->{'iter'}=$iter;
        }
        while($_=$iter->next){
            if(!$_->{'_ok_'}){
                $api->warn("Failed to retrieve pages: ".$_->{'error'}."\n");
                return 60;
            }

            next if exists($skip{$_->{'title'}});

            my $title=$_->{'title'};
            $api->log("Checking for templates in $title");

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

            # 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 actual replacements
            my %r=();
            my $paranoia=0;
            my $outtxt=$api->process_templates($intxt, sub {
                my $name=shift;
                my $params=shift;
                my $wikitext=shift;

                return undef unless exists($templates{"Template:$name"});

                my %p=();
                foreach ($api->process_paramlist(@$params)){
                    $p{$_->{'name'}}=$_->{'value'};
                }
                return undef if(exists($p{'demo'}) || exists($p{'nosubst'}));
                my $rp=$templates{"Template:$name"}(\%p, $params, $wikitext);
                return undef unless defined($rp);

                $r{$name}=1;
                $paranoia=1 if $rp eq '';
                return $rp;
            });

            # Need to edit?
            if($outtxt ne $intxt){
                my $summary="Replacing/removing expired templates: {{".join("}} {{", keys %r)."}}";
                $summary.=' (please review this edit)' if $paranoia;
                $api->log("$summary in $title");
                my $r=$api->edit($tok, $outtxt, $summary, !$paranoia, !$paranoia);
                if($r->{'code'} ne 'success'){
                    $api->warn("Write failed on $title: ".$r->{'error'}."\n");
                    next;
                }
            } else {
                $api->log("Nothing to do in $title");
            }

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

    # No more pages to check for now
    $self->{'iter'}=undef;
    $self->{'iterators'}=[@iterators];
    return 21600;
}

1;