User:MilHistBot/membership.pl
Appearance
#!/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;