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:BOT#Approval]], any bot or automated editing process that only
affects only the operators' user and talk pages (or subpages thereof),
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;