package tasks::DatedCategoryDeleterTest;
=pod
=begin metadata
Bot: AnomieBOT III
Task: DatedCategoryDeleterTest
BRFA: N/A
Status: On hold
Created: 2017-01-31
Exclusion: false
Investigation for whether a bot to [[WP:CSD#G6|G6]] emptied dated maintenance
categories would be useful. It will log to a subpage and we'll see how often it
actually finds anything.
=end metadata
=cut
use utf8;
use strict;
use AnomieBOT::Task;
use Data::Dumper;
use POSIX qw/strftime/;
use vars qw/@ISA/;
@ISA=qw/AnomieBOT::Task/;
sub new {
my $class = shift;
my $self = $class->SUPER::new();
bless $self, $class;
return $self;
}
=pod
=for info
Per [[WP:BOTUSERSPACE]], any bot or automated editing process that affects only
the operator's or their own userspace, and which are not otherwise disruptive,
may be run without prior approval.
=for info
As of 2019-02-10, there doesn't seem to be any need for this.
=cut
sub approved {
return -500;
}
sub run {
my ($self, $api) = @_;
$api->task('DatedCategoryDeleterTest', 0, 10, qw/d::Timestamp d::IWNS/);
# Easier to use the DB for category intersection
my ($dbh);
eval {
($dbh) = $api->connectToReplica( 'enwiki' );
};
if ( $@ ) {
$api->warn( "Error connecting to replica: $@\n" );
return 300;
}
my @rows;
eval {
@rows = @{ $dbh->selectall_arrayref( qq{
SELECT page_namespace, page_title
FROM page JOIN categorylinks AS c1 ON(c1.cl_from=page_id) JOIN categorylinks AS c2 ON(c2.cl_from=page_id)
WHERE c1.cl_to = 'Candidates_for_uncontroversial_speedy_deletion' AND c2.cl_to = 'Monthly_clean-up_category_counter'
}, { Slice => {} } ) };
};
if ( $@ ) {
$api->warn( "Error fetching page list from replica: $@\n" );
return 300;
}
return 3600 unless @rows;
my @woulddelete = ();
for my $row (@rows) {
return 0 if $api->halting;
next if $row->{'page_namespace'} != 14;
utf8::decode( $row->{'page_title'} ); # Data from database is binary
my $title = $row->{'page_title'};
$title =~ s/_/ /g;
my $res = $api->query(
titles => "Category talk:$title",
formatversion => 2,
);
if($res->{'code'} ne 'success') {
$api->warn("Failed to get existence for Category talk:$title: " . $res->{'error'} . "\n");
next;
}
unless ( $res->{'query'}{'pages'}[0]{'missing'} // 0 ) {
$api->log( "Skipping [[Category:$title]], talk page exists" );
next;
}
my $tok = $api->gettoken( 'csrf', Title => "Category:$title", NoExclusion => 1, categoryinfo => {} );
if($tok->{'code'} eq 'shutoff') {
$api->warn("Task disabled: " . $tok->{'content'} . "\n");
return 300;
}
if($tok->{'code'} ne 'success') {
$api->warn("Failed to get token for Category:$title: " . $tok->{'error'} . "\n");
next;
}
if ( ( $tok->{'categoryinfo'}{'size'} // 0 ) != 0 ) {
$api->log( "Skipping [[Category:$title]], not actually empty" );
next;
}
my $txt = $tok->{'revisions'}[0]{'slots'}{'main'}{'*'} // '';
unless ( $txt =~ /\s*\{\{Monthly clean[ -]up category(?:\s*\|[^\}]*)?\}\}\s*$/ ) {
$api->log( "Skipping [[Category:$title]], content isn't as expected" );
next;
}
push @woulddelete, "Category:$title";
}
if ( @woulddelete ) {
my $tok = $api->edittoken( 'User:AnomieBOT III/DatedCategoryDeleter test' );
if($tok->{'code'} eq 'shutoff') {
$api->warn("Task disabled: " . $tok->{'content'} . "\n");
return 300;
}
if($tok->{'code'} ne 'success') {
$api->warn("Failed to get token for testing log: " . $tok->{'error'} . "\n");
next;
}
my $txt = $tok->{'revisions'}[0]{'slots'}{'main'}{'*'};
$txt=~s/\s*$/\n/s;
my $time = strftime( '%Y-%m-%d %H:%M:%S', gmtime );
my $count = 0;
for my $title (@woulddelete) {
next if $txt =~ /Would delete \[\[:\Q$title\E\]\]/;
$txt .= "* [$time] Would delete [[:$title]]\n";
$count++;
}
if ( $count > 0 ) {
my $res = $api->edit($tok, $txt, "Updating testing log, +$count", 0, 1);
if ( $res->{'code'} ne 'success' ) {
$api->warn("Failed to post testing log: " . $res->{'error'} . "\n");
}
}
}
return 3600;
}
1;