User:AnomieBOT/source/tasks/IMONumberRedirectCreator.pm
Approved 2015-04-07 Wikipedia:Bots/Requests for approval/AnomieBOT 73 |
package tasks::IMONumberRedirectCreator;
=pod
=begin metadata
Bot: AnomieBOT
Task: IMONumberRedirectCreator
BRFA: Wikipedia:Bots/Requests for approval/AnomieBOT 73
Status: Approved 2015-04-07
Created: 2015-04-02
Create redirects for [[IMO numbers]], based on categorization in [[:Category:IMO numbers]].
=end metadata
=cut
use utf8;
use strict;
use AnomieBOT::Task;
use Data::Dumper;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;
sub new {
my $class = shift;
my $self = $class->SUPER::new();
$self->{'iter'} = undef;
bless $self, $class;
return $self;
}
=pod
=for info
Approved 2015-04-07<br />[[Wikipedia:Bots/Requests for approval/AnomieBOT 73]]
=cut
sub approved {
return 3;
}
sub run {
my ($self, $api) = @_;
$api->task('IMONumberRedirectCreator', 0, 10, qw/d::Redirects/);
my $screwup=' Errors? [[User:'.$api->user.'/shutoff/IMONumberRedirectCreator]]';
my $starttime = time();
my $lastrun = $api->store->{'lastrun'} // 0;
my $t = $lastrun + 86400 - $starttime;
return $t if $t > 0;
my $redir = $api->redirect_regex();
# Spend a max of 5 minutes on this task before restarting
my $endtime = time() + 300;
my $iter = $self->{'iter'};
if(!defined($iter)) {
$iter = $api->iterator(
list => 'categorymembers',
cmtitle => 'Category:IMO numbers',
cmprop => 'title|sortkeyprefix',
cmlimit => '100',
);
$self->{'iter'} = $iter;
$self->{'conflicts'} = {};
$self->{'doconflicts'} = 1;
}
while(my $n = $iter->next) {
return 0 if $api->halting;
if(!$n->{'_ok_'}) {
$api->warn("Failed to retrieve category members: " . $n->{'error'} . "\n");
$self->{'doconflicts'} = 0;
return 60;
}
next if $n->{'ns'} != 0;
my $target = $n->{'title'};
my $number = $n->{'sortkeyprefix'};
my $title = "IMO $number";
next unless $number =~ /^\d{7,8}$/; # Seems sufficient for the forseeable future
my $tok = $api->edittoken($title, EditRedir => 1);
if($tok->{'code'} eq 'shutoff') {
$api->warn("Task disabled: " . $tok->{'content'} . "\n");
$self->{'doconflicts'} = 0;
return 300;
}
if($tok->{'code'} ne 'success') {
$api->warn("Failed to get edit token for $title: " . $tok->{'error'} . "\n");
$self->{'doconflicts'} = 0;
next;
}
my $summary;
if(exists($tok->{'missing'})) {
# Doesn't exist, we can create it
$summary = "Creating redirect from [[IMO number]] to ship article [[$target]]";
} else {
# Check if it's a redirect
my $txt = $tok->{'revisions'}[0]{'slots'}{'main'}{'*'};
unless($txt=~/$redir\[\[\s*(.+?)\s*\]\]/) {
$api->log("Skipping $title: Not a redirect");
$self->{'conflicts'}{$title}{$target} = 1;
$self->{'conflicts'}{$title}{$title} = 1;
next;
}
# Is a redirect, check if it points to $target (maybe via another redir)
my $target2 = $1;
next if $target2 eq $target;
my $res = $api->query(
titles => $target2,
redirects => 1,
prop => 'categories',
clcategories => 'Category:IMO numbers',
clprop => 'sortkey',
cllimit => 'max',
);
if($res->{'code'} ne 'success') {
$api->warn("Could not resolve target page $target2: " . $res->{'error'} . "\n");
$self->{'doconflicts'} = 0;
return 60;
}
my $p = (values %{$res->{'query'}{'pages'}})[0];
my $c;
if(exists($p->{'missing'})) {
# Target page doesn't exist, so we can safely overwrite it
$api->log("Overwriting $title => $target2: target doesn't exist");
} elsif(!(($c)=grep { $_->{'title'} eq 'Category:IMO numbers' } @{$p->{'categories'} // []})) {
# Target page doesn't have the IMO Number template, so we can safely overwrite it
$api->log("Overwriting $title => $target2: target doesn't have [[Category:IMO numbers]]");
} elsif($c->{'sortkeyprefix'} ne $number) {
# Target page doesn't have the IMO Number template, so we can safely overwrite it
$api->log("Overwriting $title => $target2: target has [[Category:IMO numbers]] pointing to IMO " . $c->{'sortkeyprefix'});
} elsif(exists($res->{'query'}{'redirects'})) {
# Target page is a redirect. Overwrite if it's a double redir to our target.
if($res->{'query'}{'redirects'}[0]{'to'} ne $target) {
$api->log("Skipping $title => $target: Already a double redirect to " . $res->{'query'}{'redirects'}[0]{'to'});
$self->{'conflicts'}{$title}{$target} = 1;
$self->{'conflicts'}{$title}{$target2} = 1;
next;
}
} else {
# Target page exists and isn't a redirect. Don't edit, maybe log a message.
if(!exists($res->{'query'}{'normalized'}) || $res->{'query'}{'normalized'}[0]{'to'} ne $target) {
$api->log("Skipping $title => $target: Already a redirect to $target2");
$self->{'conflicts'}{$title}{$target} = 1;
$self->{'conflicts'}{$title}{$target2} = 1;
}
next;
}
$summary = "Updating redirect from [[IMO number]] to ship article [[$target]]";
}
my $txt = "#REDIRECT [[$target]]\n{{R from IMO number}}\n";
$api->log( "$summary in $title" );
my $res=$api->edit($tok, $txt, $summary.$screwup, 0, 1);
if($res->{'code'} ne 'success'){
$api->warn("Write for $title failed: " . $res->{'error'} . "\n");
return 60;
}
return 0 if time()>=$endtime;
}
if ( $self->{'doconflicts'} ) {
my %conflicts = %{$self->{'conflicts'}};
my $txt = "List of IMO numbers being claimed by multiple articles (via {{tl|IMO Number}} / [[:Category:IMO numbers]])\n\n";
$txt .= "This page is updated by a bot. Any changes will be overwritten periodically.\n\n";
if ( %conflicts ) {
for my $n (sort keys %conflicts) {
$txt .= "* [[$n]]: " . join( ', ', map { "[[$_]]" } sort keys %{$conflicts{$n}} ) . "\n";
}
} else {
$txt .= "There are no conflicts at this time.\n";
}
my $tok = $api->edittoken("User:AnomieBOT/IMO number conflicts", EditRedir => 1);
if($tok->{'code'} eq 'shutoff') {
$api->warn("Task disabled: " . $tok->{'content'} . "\n");
return 300;
}
if($tok->{'code'} ne 'success') {
$api->warn("Failed to get edit token for User:AnomieBOT/IMO number conflicts: " . $tok->{'error'} . "\n");
next;
}
if ( $txt ne ($tok->{'revisions'}[0]{'*'}//'') ) {
my $res=$api->edit($tok, $txt, "Updating list of IMO number conflicts. $screwup", 0, 1);
if($res->{'code'} ne 'success'){
$api->warn("Write for User:AnomieBOT/IMO number conflicts failed: " . $res->{'error'} . "\n");
return 60;
}
}
}
$self->{'iter'} = undef;
$self->{'conflicts'} = {};
return 3600 if !$self->{'doconflicts'};
$self->{'doconflicts'} = 0;
$api->store->{'lastrun'} = $starttime;
return $starttime + 86400 - time();
}
1;