User:AnomieBOT/source/tasks/POTDPageCreator.pm

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

=pod

=begin metadata

Bot:     AnomieBOT
Task:    POTDPageCreator
BRFA:    Wikipedia:Bots/Requests for approval/AnomieBOT 77
Status:  Approved 2017-02-10
Created: 2017-01-29

Create Template:POTD protected/YYYY-MM-DD two days before the corresponding
date, in time for it to be transcluded onto [[WP:Main Page/Tomorrow]].

=end metadata

=cut

use utf8;
use strict;

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

use POSIX qw/strftime/;
use Data::Dumper;

my $talk = 'Wikipedia talk:Picture of the day';

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

=pod

=for info
BRFA approved 2017-02-10<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 77]]

=cut

sub approved {
    return 2;
}

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

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

    my @now = gmtime;
    if ( ( time % 86400 ) < 86400 - 7200 ) {
        $now[3]+=1;
    } else {
        $now[3]+=2;
    }
    my $date = strftime( '%F', @now );

    my $srcpage = "Template:POTD/$date";
    my $page = "Template:POTD protected/$date";
    my @edits = ();

    my ($res, $fatal, $tok, $outtxt) = $self->process( $api, $page, $page, $srcpage );
    return $res if $res;

    if ( $outtxt=~s!^\s*\Q{{POTD/$date/{{#invoke:random|number|\E(\d+)\Q}}|{{{1|{{{style|default}}}}}}}}\E\s*!{{POTD protected/$date/{{#invoke:random|number|$1}}|{{{1|{{{style|default}}}}}}}}! ) {
        my $n = $1;
        for ( my $i = 1; $i <= $n; $i++ ) {
            my $srcpage2 = $srcpage . '/' . $i;
            my $page2 = $page . '/' . $i;
            my ($res2, $fatal, $tok2, $outtxt2) = $self->process( $api, $page, $page2, $srcpage2 );
            return $res2 if $res2 && $fatal;
            next if $res2;

            unless ( $outtxt2=~s/^\s*\Q{{POTD {{{1|{{{style|default}}}}}}\E\s*\n/{{subst:POTD row|date=$date\n/ ) {
                $api->warn( "$srcpage2 doesn't begin with expected wikitext\n$outtxt2" );
                $api->whine( "[[$srcpage2]] has unexpected content", "While attempting to create [[$page]], I found that [[$srcpage2]] does not begin with <code><nowiki>{{POTD {{{1|{{{style|default}}}}}}</nowiki></code>. Please fix it, or create [[$page]] and its subpages manually.", Pagename => $talk );
                return 60;
            }

            push @edits, [ $page2, $tok2, $outtxt2, "Creating protected version of a [[WP:POTD]] template by substing from {{[[$srcpage2|POTD/$date/$i]]|row}}" ];
        }

        push @edits, [ $page, $tok, $outtxt, "Creating protected version of a [[WP:POTD]] template by adjusting [[$srcpage]]" ];
    } elsif ( $outtxt=~s/^\s*\Q{{POTD {{{1|{{{style|default}}}}}}\E\s*\n/{{subst:POTD row\n/ ) {
        push @edits, [ $page, $tok, $outtxt, "Creating protected version of a [[WP:POTD]] template by substing from {{[[$srcpage|POTD/$date]]|row}}" ];
    } else {
        $api->warn( "$srcpage doesn't begin with expected wikitext\n$outtxt" );
        $api->whine( "[[$srcpage]] has unexpected content", "While attempting to create [[$page]], I found that [[$srcpage]] does not begin with <code><nowiki>{{POTD {{{1|{{{style|default}}}}}}</nowiki></code> or <code><nowiki>{{POTD/$date/{{#invoke:random|number|<N>}}|{{{1|{{{style|default}}}}}}}}</nowiki></code>. Please fix it, or create [[$page]] manually.", Pagename => $talk );
        return 60;
    }

    foreach my $edit (@edits) {
        my ($page, $tok, $outtxt, $summary) = @$edit;
        my $res = $api->edit($tok, $outtxt, $summary, 0, 1);
        if($res->{'code'} ne 'success'){
            $api->warn("Write for $page failed: " . $res->{'error'});
            return 60;
        }
        $api->log("Created $page");
    }

    return $self->nexttime();
}

sub process {
    my ( $self, $api, $mainpage, $page, $srcpage ) = @_;

    my $tok = $api->edittoken( $page, EditRedir => 1 );
    if($tok->{'code'} eq 'shutoff'){
        $api->warn("Task disabled: " . $tok->{'content'} . "\n");
        return (300, 1, undef, undef);
    }
    if($tok->{'code'} eq 'pageprotected'){
        $api->warn("I'm too late for $page");
        my $res = $api->query( titles => $page, formatversion => 2 );
        if ( $res->{'query'}{'pages'}[0]{'missing'} // 0 ) {
            my $andsub = $mainpage eq $page ? '' : ' and its subpages';
            $api->whine( "[[$mainpage]] was not created", "It seems that I'm too late to create [[$page]], it's already protected. Please create it$andsub manually.", Pagename => $talk );
            return ($self->nexttime(), 1, undef, undef);
        }
        return ($self->nexttime(), 0, undef, undef);
    }
    if($tok->{'code'} ne 'success'){
        $api->warn("Failed to retrieve edit token for $page: " . $tok->{'error'});
        return (60, 1, undef, undef);
    }
    unless( exists( $tok->{'missing'} ) ) {
        $api->log("$page already exists, nothing to do");
        return ($self->nexttime(), 0, undef, undef);
    }

    my $res = $api->query(
        titles => $srcpage,
        prop => 'revisions',
        rvprop => 'content',
        rvslots => 'main',
        rvlimit => 1,
        formatversion => 2,
    );
    if ( $res->{'query'}{'pages'}[0]{'missing'} // 0 ) {
        $api->warn( "$srcpage is missing!" );
        $api->whine( "[[$srcpage]] does not exist", "While attempting to create [[$mainpage]], I found that [[$srcpage]] does not exist. Please create it!", Pagename => $talk );
        return (60, 1, undef, undef);
    }

    my $intxt = $res->{'query'}{'pages'}[0]{'revisions'}[0]{'slots'}{'main'}{'content'} // '';
    # Act like preloading does
    my ($outtxt,$nowiki) = $api->strip_nowiki($intxt);
    $outtxt = join( '', $outtxt=~m!<onlyinclude>(.*?)</onlyinclude>!sg ) if $outtxt=~m!<onlyinclude>.*?</onlyinclude>!s;
    $outtxt =~ s!<noinclude>.*?</noinclude>!!sg;
    $outtxt =~ s!</?includeonly>!!g;
    $outtxt =~ s!<(?:includeonly|noinclude)\s*/>!!g;
    $outtxt = $api->replace_nowiki($outtxt, $nowiki);

    return (0, 0, $tok, $outtxt);
}

sub nexttime {
    my $t = 86400 - ( time % 86400 ) - 7200;
    return $t < 60 ? 60 : $t;
}

1;