User:AnomieBOT/source/tasks/OldIPUnblocker.pm

package tasks::OldIPUnblocker;

=pod

=begin metadata

Bot:     AnomieBOT III
Task:    OldIPUnblocker
BRFA:    Wikipedia:Bots/Requests for approval/AnomieBOT III 6
Status:  Completed 2019-05-20
Created: 2019-04-22

Unblock non-range IPs blocked in 2008 or earlier, per
[[User:AnomieBOT/req/OldIPUnblocker|Wikipedia:Village pump (proposals)#Proposal about some indefinite IP blocks]].

=end metadata

=cut

use utf8;
use strict;

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

use Data::Dumper;

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

=pod

=for info
BRFA approved 2019-05-15, Completed 2019-05-20<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT III 6]]

=cut

sub approved {
    return -500;
}

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

    $api->task('OldIPUnblocker', 0, 10);

    my $reason='Unblocking pre-2009 indefinitely-blocked IPs per [[User:AnomieBOT/req/OldIPUnblocker|RFC]]';
    my $endtime = time() + 300;

    my ($dbh);
    eval {
        ($dbh) = $api->connectToReplica( 'enwiki' );
    };
    if ( $@ ) {
        $api->warn( "Error connecting to replica: $@\n" );
        return 300;
    }

    my $fromStart = ( $self->{'cont'} eq '' );
    while ( 1 ) {
        my @rows;
        eval {
            @rows = @{ $dbh->selectall_arrayref( qq{
                SELECT ipb_id, ipb_address, ipb_timestamp
                 FROM ipblocks_ipindex
                 WHERE ipb_user = 0 AND ipb_timestamp < '20090101000000' AND ipb_expiry = 'infinity'
                  AND ipb_range_start = ipb_range_end AND (IS_IPV4(ipb_address) OR IS_IPV6(ipb_address))
                  $self->{cont}
                 ORDER BY ipb_id ASC LIMIT 1000;
            }, { Slice => {} } ) };
        };
        if ( $@ ) {
            $api->warn( "Error fetching block list from replica: $@\n" );
            return 300;
        }
        unless ( @rows ) {
            if ( !$fromStart ) {
                $fromStart = 1;
                $self->{'cont'} = '';
                next;
            }
            $api->log( 'All IPs seem to have been unblocked!' );
            return undef;
        }

        for my $row (@rows) {
            $self->{'cont'} = "AND ipb_id >= $row->{ipb_id}";
            return 0 if $api->halting;

            my $tok=$api->gettoken('csrf' );
            if ( $tok->{'code'} eq 'shutoff' ) {
                $api->warn( "Task disabled: " . $tok->{'content'} . "\n" );
                return 300;
            }
            if ( $tok->{'code'} ne 'success' ) {
                $api->warn( "Failed to get unblock token: " . $tok->{'error'} . "\n" );
                return 300;
            }

            $api->log( "Unblocking block ID $row->{ipb_id}: $row->{ipb_address} blocked $row->{ipb_timestamp}" );
            my $res = $api->action( $tok,
                action => 'unblock',
                id => $row->{'ipb_id'},
                reason => $reason,
            );
            if ( $res->{'code'} ne 'success' ) {
                $api->warn( "Failed to unblock ID  $row->{ipb_id} ($row->{ipb_address} blocked $row->{ipb_timestamp}): $res->{error}\n" );
                $fromStart = 0;
            }

            $self->{'cont'} = "AND ipb_id > $row->{ipb_id}";

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

1;