Template:NW Scan Status

From The Urban Dead Wiki
Jump to navigationJump to search


NecroWatch Scan Status Map

Usage

This template will be used to create a Map with the Scan status of all suburbs and NT Buildings in Malton. Parameters are:

  • <Suburb name>=<DangerMapnormal>type - a color for a suburb based on average scan ages in this suburb
  • <NT Building name>=<color> - a color for each NT Building based on scan age
  • <NT Building name> age=<scan age in days> - the scan age in days for each NT Building for the title-tag
{{NW Scan Status
|Dakerstown=DangerMapnormalmoderately dangerous
|Jensentown=DangerMapnormalvery dangerous
...
|The Serrell Building=#EE0|The Serrell Building age=19
|The Preston Building=Green|The Preston Building age=2
...

How it works

As the mediawiki offers no functions for calculating and date/time handling, creating an scan age map requires external processing.

Every 3 hours a shell script is run which fetches the NecroWatch pages with the scan images - i.e. NecroWatch/A_to_D up to NecroWatch/S_to_Z. The sourcecode of those pages is concatenated to one big file. After that, a Perl script is executed.

This Perl script will read the file, recognizing suburb headings, building sections and the signature and date of the last update. Based on this data the script calculates average scan age of a whole suburb and determines age levels for all buildings based on last update in days. Using the CMS::MediaWiki Perl module, the script will then connect to the UD wiki and update a template to show the changes.

Requirements

Sourcecodes

fetchsubs.sh

Shellscript for fetching scanpages, combining them to one file, then starting the perl script. As all scripts and data files should stay in a single directory, this script should changedir (cd) there first.

#!/bin/sh

# Change this to the directory where your files are
cd /home/someuser/NecroWatch

URL=http://wiki.urbandead.com/index.php/NecroWatch/

if [ -f full_listing ]
then
        cp full_listing full_listing.old
        rm full_listing
fi
touch full_listing

for PAGE in A_to_D E_to_L M_to_O P_to_R S_to_Z
do
        wget ${URL}${PAGE} >> fetch.log 2>&1
        cat ${PAGE} >> full_listing
done

for PAGE in A_to_D E_to_L M_to_O P_to_R S_to_Z
do
        rm ${PAGE}
done

./parseNWindex.pl full_listing >> parse.log 2>&1

parseNWindex.pl

Perl Script for the real work.

#!/usr/bin/perl -w

use strict;
use POSIX;
use Date::Parse;
use CMS::MediaWiki;

#####################
### Configuration ###
#####################

# UD Wiki Login information: Username/Password
my $WikiUser = 'Wikiuser';
my $WikiPass = 'secret password';
# UD Wiki Target Page Information: Page and Section
my $WikiPage = 'SomePage/InThe/Wiki';
my $WikiPageSection = 2;        # use '' for full page. 2=>edit section 2
# UD Wiki Page/Section prefix: WikiCode before map code
my $WikiPagePrefix = '= Test: Scan Age Map update =\n\n';
# UD Wiki Page/Section suffix: WikiCode after map code
my $WikiPageSuffix = '\nautomatically updated by --~~~~\n';
# UD Wiki summary: Update comment
my $WikiPageSummary = '/* Test: Scan Age Map update */  automatically updated by script';
# Template: Name of the Template
my $MapTemplate = 'User:Alka_Selzer/Sandbox1';
# Misc: Debugmessages on (=1) or off (=0)
my $Debug = 0;

##################################
### End of Configuration       ###
### Don't edit below this line ###
##################################

# Disable localization for strftime()
setlocale(LC_ALL, "C");

# HTML Indexfile should be first parameter.
if (! defined($ARGV[0])) {
        debug("No filename given, aborting\n");
        exit(1);
}
my $Indexfile = $ARGV[0];
# Check if file exists
if (! -f $Indexfile) {
        debug("$Indexfile: no such file or unreadable\n");
        exit(1);
}

debug("Using $Indexfile\n");

my $_line;
my $Now = time();
# Variables for Statekeeping
my $Suburb;
my $Building;
my $Scandate;
my $IsSummarized = 0;
# Statistics
my $BuildingCount = 0;
my $SuburbCount = 0;
# Suburb Data
my %Suburbage;
my %Buildingdata;

open(INDEX,$Indexfile) or die("cannot open $Indexfile");

while ($_line = <INDEX>) {
        # regular expression for suburb heading
        if ($_line =~ /<a name=\"(\w+?)\"><\/a>/) {
                # in case last building was not summarized, do it now
                summarize($Suburb,$Building,$Scandate) unless ($IsSummarized);
                $IsSummarized = 1;
                $Suburb = $1;
                $SuburbCount++;
                if (! defined ($Suburbage{$Suburb})) {
                        # Prepare data structure for this suburb
                        $Suburbage{$Suburb}{'count'}=0;
                        $Suburbage{$Suburb}{'avg'}=0;
                }
        }
        # regular expression for buildings
        if ($_line =~ /<a href=\"\/index\.php\/User:NTScan\/(.*?)\" title=\".*?\">Update<\/a>/) {
                # in case last building was not summarized, do it now
                summarize($Suburb,$Building,$Scandate) unless ($IsSummarized);
                $IsSummarized = 0;
                $Scandate = undef;
                $Building = $1;
                $BuildingCount++;
        }
        # regular expression for user signature and the date (hh:mm, d Month yyyy)
        if ($_line =~ /title=\".*?\">(.*?) (\d{2}:\d{2}, \d+ \w+ \d{4} \(\w+\))/) {
                my $_time = $2;
                # remove ( ) from timezone for str2time()
                $_time =~ s/[\(\)]//g;
                $Scandate = str2time($_time);
                summarize($Suburb,$Building,$Scandate);
                $IsSummarized = 1;
        }
}
close(INDEX);
# in case last building did not have a date, summerize it anyway
summarize($Suburb,$Building,$Scandate) unless ($IsSummarized);

debug("\n$BuildingCount NT-Buildings in $SuburbCount suburbs processed\n");

# Debuging - enable if neccessary
#foreach $Suburb (keys %Suburbage) {
#       my $_average = $Suburbage{$Suburb}{'avg'};
#       my $_days = int($_average/86400);
#       print "$Suburb: Age $_days days\n";
#}

# Create the template text
my $_template = mktemplate();

# fetch last template and compare - only update if things have changed
# last used template is stored in ./template.last
my $_doupdate = 0;
if ( -f "template.last" ) {
        open(LASTTEMP, "template.last");
        my $_compare="";
        my $_line;
        while ($_line = <LASTTEMP>) {
                $_compare .= $_line;
        }
        close(LASTTEMP);
        if ($_compare ne $_template) {
                # update if template has changed
                $_doupdate = 1;
        }
} else {
        # update if no template.last present
        $_doupdate = 1;
}
# do the update if $_doupdate is set
updateWiki($_template,$WikiPage,$WikiPageSection) unless (! $_doupdate);

# safe current template for reference
open(LASTTEMP, ">template.last");
print LASTTEMP $_template;
close(LASTTEMP);
# all done
exit(0);

####################
### subfunctions ###
####################

### summarize(SUBURB,BUILDING,DATE)
## calculate new suburb average based on date
## if date is not set, this will count as 90 days old
sub summarize {
        my $_sub = shift;
        my $_bld = shift;
        my $_sdt = shift;

        return if (not defined $_bld);

        debug("$_sub: Got timestamp $_sdt\n") unless (! defined $_sdt);
        if (! defined $_sdt) {
                # scandate not set, use 90 days
                $_sdt = $Now - 10368000;        # 90 days = 60*60*24*90 seconds old
        }
        elsif ($_sdt < ($Now - 10368000)) {
                # if scandate is older than 90 days, use 90 days
                $_sdt = $Now - 10368000;
        }
        # Building names may contain %28/%29, HTML code for ( and ). Replace this.
        $_bld =~ s/%28/(/g;
        $_bld =~ s/%29/)/g;
        # Store data
        $Buildingdata{$_sub}{$_bld} = $_sdt;
        debug("$_bld in the suburb $_sub : $_sdt\n");
        debug("$_sub got time of $_sdt (age: ".($Now-$_sdt)." with Now=$Now)\n");

        # calculate new average for suburb
        my $_count =  $Suburbage{$_sub}{'count'};
        my $_average = $Suburbage{$_sub}{'avg'};
        my $_diff = $Now - $_sdt;
        my $_avg = $_count * $_average;
        debug("$_sub : old count $_count, old avg $_avg\n");
        $_count++;
        $_avg += $_diff;
        $_average = $_avg/$_count;
        debug("$_sub : new count $_count, new avg $_average\n");

        # store new values
        $Suburbage{$_sub}{'count'} = $_count;
        $Suburbage{$_sub}{'avg'} = $_average;
}

### mktemplate()
## create template text from fetched data

sub mktemplate {
        my $_sub;
        my $_i = 0;
        my $_returntemplate = "";

        # Template Header
        # header
        $_returntemplate .= "{{".$MapTemplate."\n";
        # Step one: Suburb data
        foreach $_sub (keys %Suburbage) {
                my $_average = $Suburbage{$_sub}{'avg'};
                my $_days = int($_average/86400); # a day has 86400 seconds
                my $_subname = $_sub;
                # replace _ in suburb names with blanks
                $_subname =~ s/_/ /g;
                $_returntemplate .= "|$_subname=";
                if ($_days <= 7) {
                        # DangerMapnormalsafe: green on the map
                        $_returntemplate .= "DangerMapnormalsafe";
                } elsif ($_days <= 21) {
                        # DangerMapnormalmoderately dangerous: yellow on the map
                        $_returntemplate .= "DangerMapnormalmoderately dangerous";
                } elsif ($_days <= 45) {
                        # DangerMapnormaldangerous: orange on the map
                        $_returntemplate .= "DangerMapnormaldangerous";
                } else {
                        # DangerMapnormalvery dangerous: red on the map
                        $_returntemplate .= "DangerMapnormalvery dangerous";
                }
                $_i++;
                if ($_i == 2) {
                        $_returntemplate .= "\n";
                        $_i = 0;
                }
        }
        # Step two: Building data
        foreach $_sub (keys %Buildingdata) {
                my $_bld;
                my $_tmp = $Buildingdata{$_sub};
                foreach $_bld (keys %$_tmp) {
                        my $_out = $_bld;
                        # replace _ in building names with blanks
                        $_out =~ s/_/ /g;
                        $_returntemplate .= "|".$_out."=";
                        my $_age = $Now - $Buildingdata{$_sub}{$_bld};
                        my $_dage = int($_age/86400); # a day has 86400 seconds
                        if ($_dage <= 7) {
                                # Green
                                $_returntemplate .= "Green";
                        } elsif ($_dage <= 21) {
                                # #EE0: Yellow
                                $_returntemplate .= "#EE0";
                        } elsif ($_dage <= 45) {
                                # #F80: Orange
                                $_returntemplate .= "#F80";
                        } else {
                                # Red
                                $_returntemplate .= "Red";
                        }
                        # in addition to the color, give the age in days for mouseover text
                        $_returntemplate .= "|".$_out." age=";
                        if ($_dage >= 90) {
                                $_returntemplate .= "more than 90";
                        } else {
                                $_returntemplate .= $_dage;
                        }
                        $_i++;
                        if ($_i == 2) {
                                $_returntemplate .= "\n";
                                $_i = 0;
                        }
                }
        }
        $_returntemplate .= "}}\n";
        return $_returntemplate;
}

### debug(TEXT)
## prints TEXT but only if Debug=1
sub debug {
        my $_text = shift;
        print STDERR $_text unless (! $Debug);
}

### updateWiki(TEMPLATE,PAGE,SECTION)
## updates PAGE/SECTION on the Wiki using Prefix+TEMPLATE+Suffix

sub updateWiki {
        my $_content = shift;
        my $_page = shift;
        my $_section = shift;

        # create a new MediaWiki Object. Using http and wiki.urbandead.com
        my $_mw = CMS::MediaWiki->new(
                protocol => 'http',
                host => 'wiki.urbandead.com',
                debug => $Debug
        );

        # logon to wiki
        debug("Login on to wiki...\n");
        my $_rv;
        if ($_rv = $_mw->login(user => $WikiUser, pass => $WikiPass)) {
                # No success
                print STDERR "Could not login to UDWiki. Check Name and Password\n";
                print "Code: $_rv\n";
                exit($_rv);
        }
        ### For testing only: fetch old section. enable if needed
        # my $_lines = $_mw->getPage(title => $_page, section => $_section);
        #my $_i;
        #print sprintf('%08d ', ++$_i), " $_\n" foreach @$_lines;

        # Editing Wiki Page
        my $_WikiCode = $WikiPagePrefix.$_content.$WikiPageSuffix;
        $_rv = $_mw->editPage(
                title => $_page,
                section => $_section,
                text => $_WikiCode,
                summary => $WikiPageSummary
        );
        # that's it. all done.
}