User:FACBot/fac.pl

{{syntaxhighlight|lang=perl|code=
 * 1) !/usr/bin/perl -w
 * 2) fac.pl -- Pass or fail an Featured Article class review
 * 3)     This Bot runs every day, looking for featured class articles that have been promoted by a delegate
 * 4)    If it finds one, it follows the steps involved in promoting or failing it.
 * 5) Usage: fac.pl
 * 6)    21 Sep 14 Created
 * 7)     2 Sep 17 Correction for new announcements page format
 * 8)     9 Sep 17 Fix for GA templates missing oldids
 * 9)    15 Nov 17 Guard against not being able to find nomination page
 * 10)    23 Feb 18 allow bots moved to cred; some code for old articles with GA reviews on the talk page
 * 11)    26 Apr 18 Fix for .. tags on archive page
 * 1)    26 Apr 18 Fix for .. 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');

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';
 * 1) Pages used

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) { 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;            return ($old->{user}, $old->{timestamp_date}, $old->{timestamp_time}, $diff);        } else {            $old = $revision;        }    } }
 * 1)        print Dumper $revision, "\n";
 * 1)            print $diff, "\n";

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>//s;

# Tag the top and bottom of the page my $result = "promoted by $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>//s;

# Tag the top and bottom of the page my $result = "archived by $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;

return @good_article_lists; }
 * 1)    foreach (@good_article_lists) {
 * 2)        print $ARG, "\n";
 * 3)    }

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; if ($good_article_name eq $article) { $foundit = 1; next; }               }            }            if ($foundit && ! $totals_updated) { if (/\((\d+) articles\)/) { my $updated = $1 - 1; s/$1/$updated/; $totals_updated = 1; }           }            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; } }
 * 1)                     print $good_article_name, "\n";
 * 1)                    print $ARG, "\n";
 * 1)                    print $ARG, "\n";

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) {        $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; }   } }
 * 1)        print $category, "\n";

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; }       }    }    return %p; }
 * 1)    foreach my $p (keys %p) {
 * 2)        print "$p => $p{$p}\n";
 * 3)    }

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; my $has_nested_text = 0; while ($$text =~ /{{$tag[^}]+({{[^}]+}})/) { my $nested_text = $1; my $transformed_text = $nested_text; $transformed_text =~ s/{{(.+)}}/%%<$1>%%/; $$text =~ s/\Q$nested_text\E/$transformed_text/; $has_nested_text = 1; }   return $has_nested_text; }
 * 1)    print "tag='$tag'\n";
 * 1)        print "Nested text!!!!\n";
 * 1)        print "nested text='$nested_text'\n";
 * 1)        print "transformed text=$transformed_text\n";

sub reset_nested_text (\$) { my ($text) = @ARG; $$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) { my $has_nested_text = has_nested_text ('ArticleHistory', $text); for (my $id = 1;; ++$id) { if ($articleHistory =~ /action$id/) { } else { 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); }
 * 1)        print "update article history\n";
 * 1)        print "articlehistory='$articleHistory'\n";
 * 1)                print "\t\tfound action$id\n";
 * 1)                print "\t\tno $id - going with that\n";

} 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) { 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;
 * 1)            print "\tFound DYK\n";

$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) { 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); }   }
 * 1)            print "\tFound DYK\n";

$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'"); }

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; }
 * 1) Find the nomination page

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 (//) { $section_max = $1; $in_list_section++; my $a = $article; push @output_lines, $ARG, "* $article"; next; }       if ($in_list_section) { if (/^$|<\/div>|/) { $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+)\]\]/; my $delta_days = Delta_Days ($y, text_to_month ($m), $d, $timestamp->{YEAR}, text_to_month ($timestamp ->{MONTH}) ,$timestamp->{DAY}); if ($delta_days < 0) { $cred->showtime ("\t\tArticle dated $timestamp->{DAY} $timestamp->{MONTH} $timestamp->{YEAR} but page is $d $m $y -- skipping\n"); return; }
 * 1)    print "$d $m $y\n";
 * 1)    print "delta days=$delta_days\n"; # Normally positive

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",        minor => 0,    }) or        error_exit ("unable to edit '$showcase_fa'"); }
 * 1)            bot => 1,

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",            minor => 0,        }) or            error_exit ("unable to edit '$showcase_a'"); }   return $found; }
 * 1)            bot => 1,

sub is_older_nomination ($$) { my ($nomination, $twenty_days_ago) = @ARG;


 * 1)    print "$nomination\n";

my @history = $editor->get_history ($nomination) or       error_exit ("Unable to get history of '$nomination'");

my $revision = pop @history;
 * 1)    print "$revision->{timestamp_date}\n";

my $is_older_nomination = $revision->{timestamp_date} lt $twenty_days_ago; return $is_older_nomination; }
 * 1)    print $is_older_nomination ? "\tis older than twenty_days_ago\n" : "\tis NOT older than twenty_days_ago\n" ;

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));
 * 1)    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 ;

my @candidates = $editor->get_pages_in_category ('Wikipedia featured article candidates'); foreach my $talk (@candidates) {
 * 1) First, we need to find the nomination pages

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; }}