User:MilHistBot/membership.pl

From Wikipedia, the free encyclopedia
#!/usr/bin/perl -w
#
# membership.pl -- Check for inactive members of the MilHist Project
# Usage: membership.pl
#    11 Jan 18 Created
#    24 Jan 18 Process inactive list as well as active list

use English;
use strict;
use utf8;
use warnings;

use DateTime;
use DateTime::Duration;
use File::Basename;
use MediaWiki::Bot;

binmode(STDOUT, ":utf8");
binmode(STDERR, ":utf8");

my $milhist = 'Wikipedia:WikiProject Military history';
my $active_members = "$milhist/Members/Active";
my $inactive_members = "$milhist/Members/Inactive";

my $today = DateTime->today();

my $dirname = dirname (__FILE__, '.pl');
push @INC, $dirname;
require Cred;
my $cred = new Cred ();
my $log = $cred->log ();

# log in to the wiki
my $editor = MediaWiki::Bot->new({
        assert        => 'bot',
        host        => 'en.wikipedia.org',
        protocol     => 'https',
        operator     => 'Hawekeye7',
    }) or die "new MediaWiki::Bot failed";
   
$editor->login ({
    username => $cred->user,
    password => $cred->password
}) or die $editor->{error}->{code} . ': ' . $editor->{error}->{details};


sub error_exit ($) {
    my @message = @ARG;
    if ($editor->{error}->{code}) {
        push @message, ' (', $editor->{error}->{code} , ') : ' , $editor->{error}->{details};
    }
    $cred->error (@message);
}

sub error_warning ($) {
    my @message = @ARG;
    if ($editor->{error}->{code}) {
        push @message, ' (', $editor->{error}->{code} , ') : ' , $editor->{error}->{details};
    }
    $cred->warning (@message);
}

sub redirect ($) {
    my $user = shift;
    my $user_talk = "User talk:" . $user;
    my $user_talk_text = $editor->get_text ($user_talk) or do {
        error_warning ("Unable to find talk page for '$user')");
        return undef;
    };
    if ($user_talk_text =~ /#REDIRECT \[\[User talk:(.+?)\]\]/) {
        my $redirect = $1;
#        $cred->showtime ("$user redirects to $redirect\n");
        return $redirect;   
     }
    $cred->warning ("Unable to find redirect for '$user')");
     return undef;   
}

sub last_active ($) {
    my $member = shift;
    my $last_active;
    MEMBER:while (1) {   
        $last_active = $editor->last_active ($member) or do {
            $member = redirect ($member);
            if (defined $member) {
                redo MEMBER;   
            } else {
                return undef;
            }
        };
        last;
    }
    return $last_active;
}

sub days_ago ($) {
    my $latest_timestamp = shift;
    $latest_timestamp =~ /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z/;
    my $active = DateTime->new (year => $1, month => $2, day => $3, hour => $4, minute => $5, second => $6, time_zone => 'UTC');
    my $delta = $active->delta_days ($today);
    return $delta->in_units ('days');
}

my %active;
my %inactive;
my $active_count = 0;
my $inactive_count = 0;

my $inactive_members_text = $editor->get_text ($inactive_members) or
    error_exit ("Unable to find '$inactive_members')");

my @inactive_lines = split /\n/, $inactive_members_text;
my @inactive_header = grep { ! /^#/ } @inactive_lines;
my @inactive_members = grep { /^#/ } @inactive_lines;
   
INACTIVE_LINE:foreach my $inactive_line (@inactive_members) {
    my $member;
    if ($inactive_line =~ /\{\{\#target:User talk:(.+?)\}\}/) {
        $member = $1;
    } else {
        $cred->warning ("irregular line: $inactive_line\n");
        next INACTIVE_LINE;   
    }

    my $last_active = last_active ($member) or
        next INACTIVE_LINE;
       
    my $days_ago = days_ago ($last_active);
    if ($days_ago < 365) {
        $cred->showtime ("$member last active $last_active ($days_ago days ago)\n");
        $active{$inactive_line} = 1;
        ++$active_count;
    } else {
        $inactive{$inactive_line} = 1;
    }
}

my $active_members_text = $editor->get_text ($active_members) or
    error_exit ("Unable to find '$active_members')");

my @active_lines = split /\n/, $active_members_text;
my @active_header = grep { ! /^#/ } @active_lines;
my @active_members = grep { /^#/ } @active_lines;
   
ACTIVE_LINE:foreach my $active_line (@active_members) {
    my $member;
    if ($active_line =~ /\{\{\#target:User talk:(.+?)\}\}/) {
        $member = $1;
    } else {
        $cred->warning ("irregular line: $active_line\n");   
        next ACTIVE_LINE;
    }

    my $last_active = last_active ($member) or
        next ACTIVE_LINE;
       
    my $days_ago = days_ago ($last_active);
    if ($days_ago >= 365) {
        $cred->showtime ("$member last active $last_active ($days_ago days ago)\n");
        $inactive{$active_line} = 1;
        ++$inactive_count;
    } else {
        $active{$active_line} = 1;
    }
}

$cred->showtime ("$active_count active members found\n");
$cred->showtime ("$inactive_count inactive members found\n");
exit 0 unless ($active_count > 0 or $inactive_count > 0);

$cred->showtime ("updating active list\n");
$active_members_text = join "\n", @active_header, sort keys %active;

$editor->edit ({
        page => $active_members,
        text => $active_members_text,
        summary => 'update to remove members inactive for > 365 days',
        minor => 0,
    }) or
        error_exit ("unable to edit '$active_members'");

$cred->showtime ("updating inactive list\n");
$inactive_members_text = join "\n", @inactive_header, sort keys %inactive;

$editor->edit ({
        page => $inactive_members,
        text => $inactive_members_text,
        summary => 'update to add members inactive for > 365 days',
        minor => 0,
    }) or
        error_exit ("unable to edit '$active_members'");


$cred->showtime ("finished okay\n");
exit 0;