#!/usr/bin/perl -w
#
# fac.pl -- Pass or fail an Featured Article class review
# This Bot runs every day, looking for featured class articles that have been promoted by a delegate
# If it finds one, it follows the steps involved in promoting or failing it.
# Usage: fac.pl
# 21 Sep 14 Created
# 2 Sep 17 Correction for new announcements page format
# 9 Sep 17 Fix for GA templates missing oldids
# 15 Nov 17 Guard against not being able to find nomination page
# 23 Feb 18 allow bots moved to cred; some code for old articles with GA reviews on the talk page
# 26 Apr 18 Fix for <noinclude>..</noinclude> tags on archive page
use English;
use strict;
use utf8;
use warnings;
use Carp;
use Data::Dumper;
use Date::Calc qw(Delta_Days);
use Date::Parse;
use DateTime;
use File::Basename qw(dirname);
use File::Spec;
use MediaWiki::Bot;
use POSIX qw(strftime);
use XML::Simple;
binmode (STDERR, ':utf8');
binmode (STDOUT, ':utf8');
# Pages used
my $candidates_page = 'Wikipedia:featured article candidates';
my $encoded_nomination;
my $announcements = 'Template:Announcements/New featured content';
my $goings_on = 'Wikipedia:Goings-on';
my $showcase_a = 'Wikipedia:WikiProject Military history/Showcase/A';
my $showcase_fa = 'Wikipedia:WikiProject Military history/Showcase/FA';
my @months = qw(January February March April May June July August September October November December);
my $editor = MediaWiki::Bot->new ({
assert => 'bot',
host => 'en.wikipedia.org',
protocol => 'https',
operator => 'Hawkeye7',
}) or die "new MediaWiki::Bot failed";
my $dirname = dirname (__FILE__, '.pl');
push @INC, $dirname;
require Cred;
my $cred = new Cred ();
my $log = $cred->log ();
require showcase;
sub error_exit ($) {
my @message = @ARG;
if ($editor->{error}->{code}) {
push @message, ' (', $editor->{error}->{code} , ') : ' , $editor->{error}->{details};
}
$cred->error (@message);
}
sub has_been_closed ($) {
my ($nomination) = @ARG;
$cred->showtime ("checking if $nomination has been closed...\n");
my $text = $editor->get_text ($nomination) or do {
$cred->showtime ("Unable to find nomination page '$nomination')\n");
return ();
};
if ($text =~ /{{FACClosed.+ (\d+:\d+, (\d+) (\w+) (\d+))/) {
$cred->showtime ("$nomination has been closed\n");
return ($1, $2, $3, $4);
}
return ();
}
sub has_been_promoted ($$$) {
my ($nomination, $month, $year) = @ARG;
$cred->showtime ("\tchecking if $nomination has been promoted...\n");
my $log_page = "Wikipedia:Featured article candidates/Featured log/$month $year";
my $log_text = $editor->get_text ($log_page) or
error_exit ("Unable to find '$log_page')");
$log_text =~ s/_/ /g;
if ($log_text =~ /\Q$nomination\E/) {
$cred->showtime ("\tfound $nomination\n");
return 1;
}
$cred->showtime ("\t$nomination NOT promoted\n");
return 0;
}
sub has_been_archived ($$$) {
my ($nomination, $month, $year) = @ARG;
$cred->showtime ("checking if $nomination has been archived...\n");
my $log_page = "Wikipedia:Featured article candidates/Archived nominations/$month $year";
my $log_text = $editor->get_text ($log_page) or
error_exit ("Unable to find '$log_page')");
$log_text =~ s/_/ /g;
if ($log_text =~ /\Q$nomination\E/) {
$cred->showtime ("\tfound $nomination\n");
return 1;
}
$cred->showtime ("\t$nomination NOT archived\n");
return 0;
}
sub whodunnit ($$$) {
my ($article, $nomination, $action) = @ARG;
my $old;
my @history = $editor->get_history ($nomination) or
error_exit ("Unable to get history of '$nomination'");
foreach my $revision (@history) {
# print Dumper $revision, "\n";
my $text = $editor->get_text ($nomination, $revision->{revid}) or
error_exit ("Unable to find '$nomination:$revision->{revid}')");
if ($text !~ /{{FACClosed/) {
$cred->showtime ("\t$article was $action by $old->{user} at $old->{timestamp_date} $old->{timestamp_time}\n");
my $diff = "https://en.wikipedia.org/w/index.php?title=$nomination\&diff=$old->{revid}\&oldid=$revision->{revid}";
$diff =~ s/ /_/g;
# print $diff, "\n";
return ($old->{user}, $old->{timestamp_date}, $old->{timestamp_time}, $diff);
} else {
$old = $revision;
}
}
}
sub remove_from_candidates ($$) {
my ($page, $nomination) = @ARG;
$cred->showtime ("\tRemoving from the candidates page\n");
my $candidates_text = $editor->get_text ($candidates_page) or
error_exit ("Unable to find '$candidates_page')");
$candidates_text =~ s/{{$nomination}}//;
$editor->edit ({
page => $candidates_page,
text => $candidates_text,
summary => "Removing $page from FAC candidates page",
bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$candidates_page'");
}
sub promote_update_nomination_page ($$$$$) {
my ($page, $nomination, $user, $date, $diff) = @ARG;
$cred->showtime ("\tUpdating the nomination page\n");
my $text = $editor->get_text ($nomination) or
error_exit ("Unable to find '$nomination')");
# Remove transcluded article links and featured article tools
$text =~ s/<noinclude>.+?<\/noinclude>//s;
# Tag the top and bottom of the page
my $result = "'''promoted''' by [[User:$user|$user]] via ~~~ $date [$diff]";
my $top = "{{subst:Fa top|result=$result}}";
my $bottom = "{{subst:Fa bottom}}\n";
$text = join "\n", $top, $text, $bottom;
$editor->edit ({
page => $nomination,
text => $text,
summary => "Promoting '$page'",
bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$nomination'");
}
sub archive_update_nomination_page ($$$$$) {
my ($page, $nomination, $user, $date, $diff) = @ARG;
$cred->showtime ("\tUpdating the nomination page\n");
my $text = $editor->get_text ($nomination) or
error_exit ("Unable to find '$nomination')");
# Remove transcluded article links and featured article tools
$text =~ s/<noinclude>.+?<\/noinclude>//s;
# Tag the top and bottom of the page
my $result = "'''archived''' by [[User:$user|$user]] via ~~~ $date [$diff]";
my $top = "{{subst:Fa top|result=$result}}";
my $bottom = "{{subst:Fa bottom}}\n";
$text = join "\n", $top, $text, $bottom;
$editor->edit ({
page => $nomination,
text => $text,
summary => "Archiving '$page'",
bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$nomination'");
}
sub good_article_lists () {
$cred->showtime ("\tFinding the good article lists\n");
my $good_articles = 'Wikipedia:Good articles';
my $good_articles_all = "$good_articles/all";
my $text = $editor->get_text ($good_articles_all) or
error_exit ("Unable to find '$good_articles_all'");
$cred->error ("no bots allowed on '$good_articles_all'") unless $cred->allow_bots ($text);
my @good_article_lists = $text =~ /{{($good_articles\/[A-Z].+)}}/g;
# foreach (@good_article_lists) {
# print $ARG, "\n";
# }
return @good_article_lists;
}
sub update_good_article_list ($) {
my ($article) = @ARG;
$cred->showtime ("\tFinding $article in the good article list\n");
my @good_article_lists = good_article_lists ();
my $foundit = 0;
my $totals_updated = 0;
foreach my $list (@good_article_lists) {
my $text = $editor->get_text ($list) or
error_exit ("Unable to find '$list'");
$cred->error ("no bots allowed on '$list'") unless $cred->allow_bots ($text);
my @input = split /\n/, $text;
my @output;
foreach (@input) {
if (! $foundit) {
if (/\[\[([^\]\|]+)/) {
my $good_article_name = $1;
# print $good_article_name, "\n";
if ($good_article_name eq $article) {
$foundit = 1;
next;
}
}
}
if ($foundit && ! $totals_updated) {
if (/\((\d+) articles\)/) {
# print $ARG, "\n";
my $updated = $1 - 1;
s/$1/$updated/;
$totals_updated = 1;
# print $ARG, "\n";
}
}
push @output, $ARG;
}
if ($foundit) {
$text = join "\n", @output;
last;
$editor->edit ({
page => $list,
text => $text,
summary => 'update good article list',
minor => 0,
}) or
error_exit ("unable to edit '$list'");
last;
}
last;
}
}
sub promote_update_article_page ($) {
my ($page) = @ARG;
$cred->showtime ("\tUpdating the article page\n");
my $text = $editor->get_text ($page) or
error_exit ("Unable to find '$page')");
if ($text =~ s/{{good article}}//i) {
update_good_article_list ($page);
}
$text =~ s/^/{{featured article}}\n/;
$editor->edit ({
page => $page,
text => $text,
summary => "Promoting '$page' to Featured Article status",
bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$page'");
}
sub remove_from_ga ($) {
my ($page) = @ARG;
$cred->showtime ("\tRemoving from GA...\n");
my $all = 'Wikipedia:Good articles/all';
my $text = $editor->get_text ($all) or
error_exit ("Unable to find '$all')");
my @categories = $text =~/{{(Wikipedia:Good articles\/[\w\s]+?)}}/g;
foreach my $category (@categories) {
# print $category, "\n";
$text = $editor->get_text ($category) or
error_exit ("Unable to find '$category')");
$cred->error ("no bots allowed on '$category'") unless $cred->allow_bots ($text);
if ($text =~ /\Q$page\E/) {
$cred->showtime ("\t\tfound $page in $category\n");
my @a;
my $decrement_count = 0;
my @lines = split /\n/, $text;
foreach (@lines) {
if (/\Q$page\E/) {
$decrement_count = 1;
next;
}
if ($decrement_count && /(\d+) articles/) {
$decrement_count = 0;
my $count = $1 - 1;
s/\d+/$count/;
}
push @a, $ARG;
}
$text = join "\n", @a, "\n";
$editor->edit ({
page => $category,
text => $text,
summary => "$page has been promoted to Featured Article status",
bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$category'");
return;
}
}
}
sub parse_template ($@) {
my ($text, @args) = @ARG;
my %p;
while ($text =~ s/\|(\w+)\s*=\s*([^}|]+)//is) {
$p{$1}=$2;
}
my @p = split '\|', $text;
param:foreach my $p (@p) {
next param unless $p;
foreach my $arg (@args) {
if ($p =~ /^(\w+)\s*=/) {
next;
}
if (!defined $p{$arg}) {
$p{$arg} = $p;
next param;
}
}
}
# foreach my $p (keys %p) {
# print "$p => $p{$p}\n";
# }
return %p;
}
sub newaction ($$$$$$) {
my ($action, $date, $link, $result, $revid, $id) = @ARG;
my $newaction = join "\n",
"|action${id}=$action",
"|action${id}date=$date",
"|action${id}link=$link",
"|action${id}result=$result",
"|action${id}oldid=$revid";
return $newaction;
}
sub has_nested_text ($\$) {
my ($tag, $text) = @ARG;
# print "tag='$tag'\n";
my $has_nested_text = 0;
while ($$text =~ /{{$tag[^}]+({{[^}]+}})/) {
# print "Nested text!!!!\n";
my $nested_text = $1;
# print "nested text='$nested_text'\n";
my $transformed_text = $nested_text;
$transformed_text =~ s/{{(.+)}}/%%<$1>%%/;
# print "transformed text=$transformed_text\n";
$$text =~ s/\Q$nested_text\E/$transformed_text/;
$has_nested_text = 1;
}
return $has_nested_text;
}
sub reset_nested_text (\$) {
my ($text) = @ARG;
$$text =~ s/%%</{{/g;
$$text =~ s/>%%/}}/g;
}
sub update_article_history ($$$$$$) {
my ($text, $action, $date, $link, $result, $revid) = @ARG;
$text =~ s/{{Article\s*History/{{ArticleHistory/is;
my ($articleHistory) = $text =~ /{{ArticleHistory(.+)}}/gis;
if ($articleHistory) {
# print "update article history\n";
my $has_nested_text = has_nested_text ('ArticleHistory', $text);
# print "articlehistory='$articleHistory'\n";
for (my $id = 1;; ++$id) {
if ($articleHistory =~ /action$id/) {
# print "\t\tfound action$id\n";
} else {
# print "\t\tno $id - going with that\n";
my $newaction = newaction ($action, $date, $link, $result, $revid, $id);
$text =~ s/{{ArticleHistory(.+?)}}/{{ArticleHistory$1\n$newaction\n}}/is;
last;
}
}
if ($has_nested_text) {
reset_nested_text ($text);
}
} else {
my $newaction = newaction ($action, $date, $link, $result, $revid, 1);
$text =~ s/^/{{ArticleHistory\n$newaction\n}}\n/is;
}
return $text;
}
sub get_revid ($$$) {
my ($page, $date, $time) = @ARG;
my @history = $editor->get_history ($page) or
error_exit ("Unable to get history of '$page'");
foreach my $history (@history) {
if ("$history->{timestamp_date} $history->{timestamp_time}" le "$date $time") {
return $history->{revid};
}
}
error_exit ("Unable to get revid of '$page')");
}
sub parse_display_date ($) {
my ($display_date) = @ARG;
my ($ss, $mm, $hh, $day, $month, $year, $zone) = strptime ($display_date) or
error_exit ("Unable to parse date '$display_date'");
my $dt = DateTime->new (
year => 1900 + $year,
month => 1 + $month,
day => $day,
hour => $hh // 0,
minute => $mm // 0,
second => $ss // 0,
);
my $date = $dt->strftime ("%Y-%m-%d");
my $time = $dt->strftime ("%H:%M");
return ($time, $date);
}
sub add_ga_to_history ($$$) {
my ($article, $text, $talk) = @ARG;
if ($text =~ s/{{GA[^m](.+?)}}//is) {
my %h = parse_template ($1, 'date', 'oldid', 'page', 'topic');
my $revid = $h{oldid};
my $display_date = $h{date};
my $gaid = $h{page} // 1;
my $link = "$talk/GA$gaid";
if (!defined $revid || $revid !~ /\d+/) {
my ($time, $date) = parse_display_date ($display_date);
$revid = get_revid ($article, $date, $time);
}
$text = update_article_history ($text, 'GAN', $display_date, $link, 'listed', $revid);
}
return $text;
}
sub add_pr_to_history ($$) {
my ($page, $text) = @ARG;
$cred->showtime ("\tFound old Peer Review\n");
while ($text =~ s/{{oldpeerreview(.+?)}}//is) {
my %h = parse_template ($1, 'name', 'archive');
my $name = $h{name} // $page;
my $archive = defined $h{archive} ? "/archive$h{archive}" : '';
my $link = "Wikipedia:Peer_review/$name$archive";
my ($history) = $editor->get_history ($link) or
error_exit ("Unable to get history of '$link'");
my $date = $history->{timestamp_date};
my $time = $history->{timestamp_time};
my $revid = get_revid ($page, $date, $time);
$text = update_article_history ($text, 'PR', $date, $link, 'reviewed ', $revid);
}
return $text;
}
sub promote_update_talk_page ($$$$$) {
my ($page, $talk, $nomination_page, $date, $time) = @ARG;
$cred->showtime ("\tUpdating the talk page\n");
my $text = $editor->get_text ($talk) or
error_exit ("Unable to find '$talk')");
# Remove the candidacy
$text =~ s/{{featured article candidates\|.+?}}//;
# Remove from GA
if ($text =~ /{{GA[^L].+?}}/gis) { # NOT GAList - from some really old talk pages that include the GA assessment
if ($text !~ /{{GA Nominee/i) { # Happens when a GA Nominee is nominated for FAC
$text = add_ga_to_history ($page, $text, $talk);
remove_from_ga ($page);
}
} elsif ($text =~ /currentstatus=GA/gi || $text =~ /class=GA/gi) {
remove_from_ga ($page);
}
# add an old Peer review, if any, to the article history
if ($text =~ /{{oldpeerreview.+?}}/gis) {
$text = add_pr_to_history ($page, $text);
}
# Update the article history
my $revid = get_revid ($page, $date, $time);
$text = update_article_history ($text, 'FAC', $date, $nomination_page, 'promoted', $revid);
unless ($text =~ s/currentstatus\s*=\s*\w+/currentstatus=FA/is) {
$text =~ s/{{Article\s*History/{{ArticleHistory\n|currentstatus=FA\n/is;
}
# Add DYK, if any, to the article history
my $tag;
if ($text =~ /\{\{(DYK talk|dyktalk)/) {
$tag = $1;
}
if ($tag) {
my $has_nested_text = has_nested_text ($tag, $text);
if ($text =~ s/{{$tag\|(.+?)\|(\d+)\|entry=(.+?)}}//is) {
# print "\tFound DYK\n";
my $dykdate="$1 $2";
my $dykentry = $3;
$text =~ s/currentstatus=FA/currentstatus=FA\n\n|dykdate=$dykdate\n|dykentry=$dykentry/is;
}
if ($has_nested_text) {
reset_nested_text ($text);
}
}
# Update the class for all projects
$text =~ s/([^-]class)\s*=\s*(\w+)/$1=FA/igs;
$editor->edit ({
page => $talk,
text => $text,
summary => "Promoting '$page' to Featured Article status",
bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$talk'");
}
sub archive_update_talk_page ($$$$$) {
my ($page, $talk, $nomination_page, $date, $time) = @ARG;
$cred->showtime ("\tUpdating the talk page\n");
my $text = $editor->get_text ($talk) or
error_exit ("Unable to find '$talk')");
# Remove the candidacy
$text =~ s/{{featured article candidates\|.+?}}//;
# Add the GA review, if any, to the article history
if ($text =~ /{{GA[^L].+?}}/gis) {
$text = add_ga_to_history ($page, $text, $talk);
}
# add an old Peer review, if any, to the article history
if ($text =~ /{{oldpeerreview.+?}}/gis) {
$text = add_pr_to_history ($page, $text);
}
# Update the article history
my $revid = get_revid ($page, $date, $time);
$text = update_article_history ($text, 'FAC', $date, $nomination_page, 'failed', $revid);
# Update the current status
unless ($text =~ /currentstatus\s*=\s*.+/is) {
if ($text =~ /class\s*=\s*GA/is) {
$text =~ s/{{Article\s*History/{{ArticleHistory\n|currentstatus=GA\n/is;
}
}
# Add DYK, if any, to the article history
my $tag;
if ($text =~ /\{\{(DYK talk|dyktalk)/) {
$tag = $1;
}
if ($tag) {
my $has_nested_text = has_nested_text ($tag, $text);
if ($text =~ s/{{$tag\|(.+?)\|(\d+)\|entry=(.+?)}}//is) {
# print "\tFound DYK\n";
my $dykdate="$1 $2";
my $dykentry = $3;
$text =~ s/currentstatus=FA/currentstatus=FA\n\n|dykdate=$dykdate\n|dykentry=$dykentry/is;
}
if ($has_nested_text) {
reset_nested_text ($text);
}
}
$editor->edit ({
page => $talk,
text => $text,
summary => "Updating '$page' after unsuccessful Featured Article nomination",
bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$talk'");
}
# Find the nomination page
sub nomination ($) {
my ($talk) = @ARG;
my $text = $editor->get_text ($talk) or
error_exit ("Unable to find '$talk')");
$text =~ /{{featured article candidates\|(.+?\/archive\d+)/;
error_exit ("Unable to find featured article candidates template in '$talk'") unless $1;
my $nomination = "Wikipedia:Featured article candidates/$1";
$encoded_nomination = $nomination;
$nomination =~ s/&#([0-9a-f]+);/chr($1)/ige;
$cred->showtime ("\t$nomination\n");
return $nomination;
}
sub update_announcements_page ($) {
$cred->showtime ("\tUpdating the announcements page\n");
my ($article) = @ARG;
my $text = $editor->get_text ($announcements) or
error_exit ("Unable to find '$announcements'");
$cred->error ("no bots allowed on '$announcements'") unless $cred->allow_bots ($text);
if ($text =~ /\Q$article\E/) {
$cred->showtime ("\t\tAlready updated -- skipping\n");
return;
}
my $in_list_section = 0;
my $section_max;
my @input_lines = split /\n/, $text;
my @output_lines;
foreach (@input_lines) {
if (/<!-- Articles \((\d+), most recent first\) -->/) {
$section_max = $1;
$in_list_section++;
my $a = $article;
push @output_lines, $ARG, "* [[$article]]";
next;
}
if ($in_list_section) {
if (/^$|<\/div>|<!-- Topics \(\d+, most recent first\) -->/) {
$in_list_section = 0;
} elsif ($in_list_section < $section_max) {
$in_list_section++;
} else {
next;
}
}
push @output_lines, $ARG;
}
$text = join "\n", @output_lines;
$editor->edit ({
page => $announcements,
text => $text,
summary => "$article promoted to Featured Article status",
minor => 0,
}) or
error_exit ("unable to edit '$announcements'");
}
sub text_to_month ($) {
my ($month) = @ARG;
for my $i (0..11) {
if ($months[$i] eq $month) {
return $i + 1;
}
}
}
sub update_goings_on_page ($$) {
$cred->showtime ("\tUpdating the goings_on page\n");
my ($article, $timestamp) = @ARG;
my $text = $editor->get_text ($goings_on) or
error_exit ("Unable to find '$goings_on'");
$cred->error ("no bots allowed on '$goings_on'") unless $cred->allow_bots ($text);
my ($m, $d, $y) = $text =~ /week starting Sunday, \[\[(\w+) (\d+)\]\], \[\[(\d+)\]\]/;
# print "$d $m $y\n";
my $delta_days = Delta_Days ($y, text_to_month ($m), $d, $timestamp->{YEAR}, text_to_month ($timestamp ->{MONTH}) ,$timestamp->{DAY});
# print "delta days=$delta_days\n"; # Normally positive
if ($delta_days < 0) {
$cred->showtime ("\t\tArticle dated $timestamp->{DAY} $timestamp->{MONTH} $timestamp->{YEAR} but page is $d $m $y -- skipping\n");
return;
}
if ($text =~ /\Q$article\E/) {
$cred->showtime ("\t\tAlready updated -- skipping\n");
return;
}
my $abbr = substr ($timestamp->{MONTH}, 0, 3);
my $day = $timestamp->{DAY};
$day =~ s/^0//;
my $date = "$day $abbr";
my $in_list_section = 0;
my @input_lines = split /\n/, $text;
my @output_lines;
foreach (@input_lines) {
if (/Wikipedia:Featured articles/) {
$in_list_section = 1;
}
if ($in_list_section) {
if (/^$|Wikipedia:Featured lists/) {
$in_list_section = 0;
push @output_lines, "* [[$article]] ($date)";
}
}
push @output_lines, $ARG;
}
$text = join "\n", @output_lines;
$editor->edit ({
page => $goings_on,
text => $text,
summary => "$article promoted to Featured Article status",
minor => 0,
}) or
error_exit ("unable to edit '$goings_on'");
}
sub add_to_showcase ($) {
my ($article) = @ARG;
my $showcase_text = $editor->get_text ($showcase_fa) or
error_exit ("Unable to find '$showcase_fa'");
$cred->error ("no bots allowed on '$showcase_fa'") unless $cred->allow_bots ($showcase_text);
my $showcase = new showcase ($showcase_text);
$showcase->add ($article);
$editor->edit ({
page => $showcase_fa,
text => $showcase->text,
summary => "'$article' has been promoted to Featured Article status",
# bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$showcase_fa'");
}
sub remove_from_showcase ($) {
my ($article) = @ARG;
my $showcase_text = $editor->get_text ($showcase_a) or
error_exit ("Unable to find '$showcase_a'");
$cred->error ("no bots allowed on '$showcase_a'") unless $cred->allow_bots ($showcase_text);
my $showcase = new showcase ($showcase_text);
my $found = $showcase->del ($article);
if ($found) {
$editor->edit ({
page => $showcase_a,
text => $showcase->text,
summary => "'$article' has been promoted to Featured Article status",
# bot => 1,
minor => 0,
}) or
error_exit ("unable to edit '$showcase_a'");
}
return $found;
}
sub is_older_nomination ($$) {
my ($nomination, $twenty_days_ago) = @ARG;
# print "$nomination\n";
my @history = $editor->get_history ($nomination) or
error_exit ("Unable to get history of '$nomination'");
my $revision = pop @history;
# print "$revision->{timestamp_date}\n";
my $is_older_nomination = $revision->{timestamp_date} lt $twenty_days_ago;
# print $is_older_nomination ? "\tis older than twenty_days_ago\n" : "\tis NOT older than twenty_days_ago\n" ;
return $is_older_nomination;
}
sub move_the_daily_marker () {
my $text = $editor->get_text ($candidates_page) or
error_exit ("Unable to find '$candidates_page'");
$cred->error ("no bots allowed on '$candidates_page'") unless $cred->allow_bots ($text);
my @input = split /\n/, $text;
my @output;
my $nominations = 0;
my @older_nominations;
my $older_nominations = 0;
$cred->showtime ("Move the daily marker\n");
my $twenty_days_ago = strftime ('%Y-%m-%d', gmtime(time () - 20 * 24 * 60 * 60));
# print "twenty days ago was $twenty_days_ago\n";
foreach (@input) {
if (/<!--|-->/) {
}elsif (/==Nominations==/) {
$nominations = 1;
} elsif (/==Older nominations==/) {
$older_nominations = 1;
$nominations = 0;
} elsif ($nominations) {
if (/{{(Wikipedia:Featured article candidates.+)}}/) {
my $nomination = $1;
if (is_older_nomination ($nomination, $twenty_days_ago)) {
push @older_nominations, "{{$nomination}}";
next;
}
}
} elsif ($older_nominations) {
if (@older_nominations) {
push @output, @older_nominations;
$older_nominations = 0;
}
}
push @output, $ARG;
}
unless (@older_nominations) {
$cred->showtime ("No need to reset daily marker\n");
return;
}
$text = join "\n", @output;
$editor->edit ({
page => $candidates_page,
text => $text,
summary => 'update daily marker',
minor => 0,
}) or
error_exit ("unable to edit '$candidates_page'");
$cred->showtime ("Daily marker reset\n");
}
$editor->login ({
username => $cred->user,
password => $cred->password
}) or error_exit ("login failed");
$cred->showtime ("========== Commenced ==========\n");
move_the_daily_marker ();
# First, we need to find the nomination pages
my @candidates = $editor->get_pages_in_category ('Wikipedia featured article candidates');
foreach my $talk (@candidates) {
my $article = $talk;
$article =~ s/Talk:// or
next;
my $nomination = nomination ($talk);
if (my ($display_date, $day, $month, $year) = has_been_closed ($nomination)) {
$cred->showtime ("\t$nomination closed on $display_date\n");
if (has_been_promoted ($nomination, $month, $year)) {
my ($user, $date, $time, $diff) = whodunnit ($article, $nomination, 'promoted');
promote_update_talk_page ($article, $talk, $nomination, $date, $time);
promote_update_nomination_page ($article, $nomination, $user, $display_date, $diff);
promote_update_article_page ($article);
update_announcements_page ($article);
update_goings_on_page ($article, {YEAR => $year, MONTH => $month, DAY => $day});
my $found = remove_from_showcase ($article);
add_to_showcase ($article) if $found;
} elsif (has_been_archived ($nomination, $month, $year)) {
my ($user, $date, $time, $diff) = whodunnit ($article, $nomination, 'archived');
archive_update_talk_page ($article, $talk, $nomination, $date, $time);
archive_update_nomination_page ($article, $nomination, $user, $display_date, $diff);
} else {
$cred->showtime ("WARNING: FAC closed but $nomination has NOT been moved to the archive page\n");
}
} else {
$cred->showtime ("\t$nomination is still current\n");
}
}
$cred->showtime ("finished okay\n");
exit 0;