Jump to content

User:HBC AIV helperbot/source: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
H (talk | contribs)
cleanup
H (talk | contribs)
Added {{userlinks|user}} recognition
Line 90: Line 90:
foreach my $line (@content)
foreach my $line (@content)
{
{
($line =~ m/vandal\|\s*(.*?)\s*\}\}/i) || next(); # Go to next line if there is not a vandal template on this one.
($line =~ m/(vandal|userlinks)\|\s*(.*?)\s*\}\}/i) || next(); # Go to next line if there is not a vandal template on this one.
my $user = $1; # Extract username from template
my $user = $2; # Extract username from template
next if ($user eq 'username'); # Skip the examples {{vandal|username}} {{ipvandal|username}}
next if ($user eq 'username'); # Skip the examples {{vandal|username}} {{ipvandal|username}} {{userlinks|username}}
$report_count++;
$report_count++;
add_job([\&check_user,$c,$user,$page],0) if (lc($remove_blocked) eq 'on'); # Queue a check_user job for the user to run ASAP
add_job([\&check_user,$c,$user,$page],0) if (lc($remove_blocked) eq 'on'); # Queue a check_user job for the user to run ASAP
Line 198: Line 198:
{
{
my $line = shift(@content);
my $line = shift(@content);
unless ($line =~ m/vandal\|\s*$re_user\s*\}\}/i)
unless ($line =~ m/(userlinks|vandal)\|\s*$re_user\s*\}\}/i)
{
{
push(@new_content,$line);
push(@new_content,$line);
next if ($line =~ m/vandal\|username/);
next if ($line =~ m/(userlinks|vandal)\|username/i);
if($line =~ m/\{\{IPvandal\|/i)
if($line =~ m/\{\{IPvandal\|/i)
{
{
$ips_left++;
$ips_left++;
}
}
elsif($line =~ m/\{\{vandal\|/i)
elsif($line =~ m/\{\{(userlinks|vandal)\|/i)
{
{
$users_left++;
$users_left++;
Line 214: Line 214:
{
{
$found = 1;
$found = 1;
while ((scalar(@content)) && !($content[0] =~ m/\{\{I?P?vandal\|/i))
while ((scalar(@content)) && !($content[0] =~ m/\{\{(userlinks|I?P?vandal)\|/i))
{
{
my $removed = shift(@content);
my $removed = shift(@content);

Revision as of 20:52, 22 January 2007

This source is released under GFDL. Enjoy.

Note This code uses a version of the MediaWiki module that I repaired, all official versions are not functioning with the current mediawiki servers, so I fixed it. If you wish to reproduce this script you can e-mail me for the repaired mediawiki.pm file. HighInBC (Need help? Ask me) 03:37, 3 January 2007 (UTC)

use strict;
use MediaWiki;
use URI::Escape;
use Time::Local;

my $VERSION = 'HBC AIV helperbot v1.2.5 - Testing';
my $read_rate = 10;
my $write_rate = 10;

my(@pages_to_watch) =
 (
  'Wikipedia:Administrator intervention against vandalism',
  'Wikipedia:Administrator intervention against vandalism/TB2',
 );

open(PASS,'password');			# A file with only the password, no carraige return
sysread(PASS, my $password, -s(PASS));	# No password in sourcecode.
close(PASS);
my $c                  =   MediaWiki->new;
$c->setup
                        ({
                          'bot' => {'user' => 'HBC AIV helperbot','pass' => $password},
                          'wiki' => {'host' => 'en.wikipedia.org','path' => 'w'}
                        }) || die "Failed to log in\n";
my $whoami		=  $c->user();
warn "$whoami connected\n";
# The program runs in this loop which handles a queue of jobs.
my(@job_list);
my $timing = 0;
foreach my $page (@pages_to_watch)
  {
  add_job([\&check_page,$c,$page],$timing);
  $timing += 5;
  }

while (1)				# Infinite loop, a serpent biting it's own tail.
  {
  sleep(1);				# Important in all infinite loops to keep it calm
  my (@kept_jobs);			# A place to put jobs not ready to run yet
  while (my $job = shift(@job_list))	# Go through each job pending
    {
    my($r_job , $timing) = @{$job};
    if ($timing < time())		# If it is time to run it then run it
      {
      if (ref($r_job) eq 'ARRAY')	# Callback style, reference an array with a sub followed by paramaters
        {
        my $cmd = shift(@{$r_job});
        &{$cmd}(@{$r_job});
        }
      elsif (ref($r_job) eq 'CODE')	# Otherwise just the reference to the sub
        {
        &{$r_job};
        }
      }
    else				# If it is not time yet, save it for later
      {
      push(@kept_jobs , $job)
      }
    }
  push (@job_list , @kept_jobs);	# Keep jobs that are still pending
  }

sub add_job	# Command to add a job to the queue
  {
  my ($r_job , $timing) = @_;
  push (@job_list , [$r_job , (time()+$timing)]);
  }

sub check_page	# Read the page and gather usernames, give each use a check_user job on the queue
  {		# Then add Check_page to the queue scheduled for $read_rate seconds
  my $c = shift;
  my $page = shift;
  add_job([\&check_page,$c,$page],$read_rate);	# Schedule myself $read_rate seconds later
  my ($report_count);
  # Get page, read only
  my $content =  $c->get($page, 'r')->{'content'};
  unless ($content =~ m|\{\{(n?o?adminbacklog)\}\} <\!-- RemoveBlocked=([^ ]+) AutoBacklog=([^ ]+) AddLimit=(\d+) RemoveLimit=(\d+) -->|i)
    {
    warn "Could not find paramater string, not doing anything: $page\n";
    next;
    }
  my($ab_current, $remove_blocked, $auto_backlog, $ab_add,$ab_remove) = ($1,$2,$3,$4,$5);
  ($auto_backlog = undef) if ($ab_add <= $ab_remove);
  my @content = split("\n",$content); # Split into lines
  foreach my $line (@content)
    {
    ($line =~ m/(vandal|userlinks)\|\s*(.*?)\s*\}\}/i)	|| next(); # Go to next line if there is not a vandal template on this one.
    my $user = $2;				# Extract username from template
    next if ($user eq 'username');		# Skip the examples {{vandal|username}} {{ipvandal|username}} {{userlinks|username}}
    $report_count++;
    add_job([\&check_user,$c,$user,$page],0) if (lc($remove_blocked) eq 'on');	# Queue a check_user job for the user to run ASAP
    }

  if (lc($auto_backlog) eq 'on')
    {
    add_job([\&set_backlog,$c,$page,$report_count,$ab_add,$ab_remove],0)
     if 	((($report_count >= $ab_add)    && ($ab_current eq 'noadminbacklog')) ||
    		 (($report_count <= $ab_remove) && ($ab_current eq   'adminbacklog')));
    }
  return;
  }

sub set_backlog
  {
  my ($c, $page_name, $report_count,$ab_add,$ab_remove) = @_;
  $report_count ||= '0';
  my $page = $c->get($page_name, 'rw'); # Get page read/write
  my(@content) = split("\n",$page->{'content'}); # Split into lines
  my(@new_content); # Place to put replacement content
  foreach my $line (@content)
    {
    if ($line =~ m|\{\{n?o?adminbacklog\}\} <\!-- RemoveBlocked=[^ ]+ AutoBacklog=[^ ]+ AddLimit=\d+ RemoveLimit=\d+ -->|i)
      {
      if	($report_count >= $ab_add)
        {
        warn "Backlog added from: $page_name\n";
        $page->{'summary'} = 'Noticeboard is backlogged. '.$report_count.' reports need attention.';
        $line =~ s|\{\{noadminbacklog|\{\{adminbacklog|i;
        push (@new_content,$line);
        }
      elsif	($report_count <= $ab_remove)
        {
        warn "Backlog removed from: $page_name\n";
        $page->{'summary'} = 'Noticeboard is no longer backlogged. '.$report_count.' reports need attention.';
        $line =~ s|\{\{adminbacklog|\{\{noadminbacklog|i;
        push (@new_content,$line);
        }
      }
    else
      {
      push(@new_content,$line);
      }
    }
  $page->{'content'} = join("\n",@new_content);
  return unless($page->{'content'});
  $page->save();
  }

sub check_user	# Determine if the user is blocked, if so gather information about the block
  {		# and shedule a remove_name job with all the information passed along
  my $c = shift;
  my $user = shift; # Username passed from check_page
  my $page = shift;
  my $url = $c->{index}.'?title=Special:Ipblocklist&ip='.uri_escape($user);
  my $data = $c->{ua}->get($url)->content(); # Get blocklist info for user
  if ($data =~ m|</a>\) blocked <a href|)	# If the user is currently blocked
    {
    # Get name of blocking admin
    ($data =~ m|\d{2}, <a href="/wiki/User:(.*?)" title=|) || ($data =~ m|\d{2}, <a href="/w/index\.php\?title=User:(.*?)&|); #"
    my $blocker = uri_unescape($1);
    # Get expiry time of block, starting time of block, and calculate total time
    my $duration;
    if ($data =~ m|expires (\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})|)	# Match expiry time if one exists
      {
      my $expiry = timegm($6,$5,$4,$3,$2-1,$1);	# Parse expiry time
      $data =~ (m|<ul><li>(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}),|); # Match starting time
      my $block_time = timegm($6,$5,$4,$3,$2-1,$1); # Parse starting time
      $duration = timeconv($expiry - $block_time); # Pretty print the difference via timeconv (see below)
      }
    elsif($data =~ m|infinite|)	# If there is no expiry and the word 'infinite' is found
      {
      $duration = 'indef'; # Set to indef
      }
    # Get block type flags
    my(@flags);
    (push(@flags,'AO')) if ($data =~ m|anon\. only|);			# Match anon only
    (push(@flags,'ACB')) if ($data =~ m|account creation blocked|);	# Match account creation blocked
    (push(@flags,'ABD')) if ($data =~ m|autoblock disabled|);		# Match autoblock disabled
    my $block_type; # Build empty string
    # If any flag exists build a flag string.
    $block_type = '[[User:HBC AIV helperbot/Legend|('.join(' ',@flags).')]]' if (scalar(@flags));
    add_job([\&remove_name,$c,$user,$blocker,$duration,$block_type,$page],0); # Queue a remove_name job to run ASAP
    }
  }

sub remove_name
  {
  my $c = shift;
  my $user = shift;		#|Passed from check_user
  my $blocker = shift;		#|
  my $duration = shift;		#|
  my $block_type = shift;	#|
  my $page_name = shift;
  my $re_user = $user;
  $re_user =~ s|[\$\@]|.|g;
  my $page = $c->get($page_name, 'rw'); # Get page read/write
  my($ips_left,$users_left) =  ('0','0'); # Start these with 0 instead of undef
  my(@content) = split("\n",$page->{'content'}); # Split into lines
  my(@new_content); # Place to put replacement content
  my $found;
  my $lines_skipped;
  while (scalar(@content))
    {
    my $line = shift(@content);
    unless ($line =~ m/(userlinks|vandal)\|\s*$re_user\s*\}\}/i)
      {
      push(@new_content,$line);
      next if ($line =~ m/(userlinks|vandal)\|username/i);
      if($line =~ m/\{\{IPvandal\|/i)
        {
        $ips_left++;
        }
      elsif($line =~ m/\{\{(userlinks|vandal)\|/i)
        {
        $users_left++;
        }
      }
    else
      {
      $found = 1;
      while ((scalar(@content)) && !($content[0] =~ m/\{\{(userlinks|I?P?vandal)\|/i))
        {
        my $removed = shift(@content);
        $lines_skipped++ if (length($removed) > 0);
        }
      }
    }
  $page->{'content'} = join("\n",@new_content);
  return unless($found);
  return unless($page->{'content'});
  my $length = ((defined($duration)) ? (' '.$duration) : (''));
  $length = ' indef ' if ($duration eq 'indef');
  my $tally = (($ips_left || $users_left) ? ($ips_left.' IP(s) & '.$users_left.' User(s) left.') : ('List empty.'));
  my $skipped = (($lines_skipped) ? (" $lines_skipped comment(s) removed.\n") : (''));
  $page->{'summary'} = 'rm [[Special:Contributions/'.$user.'|'.$user.']] (blocked'.$length.'by [[User:'.$blocker.'|'.$blocker.']] '.$block_type.'). '.$skipped.$tally;
  $page->save();
  warn "rm '$user': $page_name\n";
  sleep($write_rate);
  }

sub timeconv
  {
  my($seconds)	= $_[0];
  return (undef) unless ($seconds);
  my($result , $used);
  my($weeks)	 = int($seconds/604800);
  $used		+= ($weeks*604800);
  my($days)	 = int(($seconds - $used)/86400);
  $used		+= ($days*86400);
  my($hours)	 = int(($seconds - $used)/3600);
  $used		+= ($hours*3600);
  my($minutes)	 = int(($seconds - $used)/60);
  $result	.= $weeks.   ' week(s) '	if ($weeks);
  $result	.= $days.   ' day(s) '		if ($days);
  $result	.= $hours.  ' hour(s) '		if ($hours);
  $result	.= $minutes.' minute(s) '	if ($minutes);
  die ("Something went wrong with the duration calculation, got negative number: $seconds\n") if (($seconds < 0) || ($weeks < 0) || ($days < 0) || ($hours < 0) || ($minutes < 0));
  return($result);
  }