denny/ShinyCMS

View on GitHub
tasks/ccbill-check-access

Summary

Maintainability
Test Coverage
#!/usr/bin/env perl

# ===================================================================
# File:        ccbill-check-access
# Project:    ShinyCMS
# Purpose:    Check if CCBill subscription customers have renewed their access
# 
# Author:    Denny de la Haye <2019@denny.me>
# Copyright (c) 2009-2019 Denny de la Haye
# 
# ShinyCMS is free software; you can redistribute it and/or modify it
# under the terms of either the GPL 2.0 or the Artistic License 2.0
# ===================================================================

use strict;
use warnings;


# Load local modules
use FindBin qw( $Bin );
use lib "$Bin/../lib";
use ShinyCMS;
use ShinyCMS::Schema;


# Exit if already running
use File::Pid;
my $pidfile = File::Pid->new({
    file => '/tmp/shinycms-ccbill-check-access.'. ShinyCMS->config->{ domain } .'.pid',
});
if ( my $num = $pidfile->running ) {
    die "Already running: $num\n";
}
$pidfile->write;

# Load CPAN modules
use DateTime;
use DateTime::Format::ISO8601;
use LWP::UserAgent;
use Text::CSV;
use Data::Dumper;


# Configure debug output level
my $debug = 1;

# Configure whether to make test mode requests or not
my $testmode = 1;    # 0 for normal/live mode, 1 for test mode


# Get the current date and time
my $now = DateTime->now;

# Get a database connection
my $schema = ShinyCMS::Schema->connect(
    ShinyCMS->config->{ 'Model::DB' }->{ connect_info }
);


# Fetch the active members list from CCBill (or use on-disk copy if one exists for today)
my $csv_data;
my $date = $now->ymd;
if ( -f $Bin.'/'.$date.'.csv' ) {
    print "Using backup file...\n" if $debug;
    {
        local $/ = undef;
        open my $backup, '<', $Bin.'/'.$date.'.csv' or die "Failed to open backup CSV file: $!";
        $csv_data = <$backup>;
        close $backup;
    }
}
else {
    print "Fetching subscription data from CCBill...\n" if $debug;
    my $account  = ShinyCMS->config->{'ccbill-check-access'}->{ account  };
    my $subacc   = ShinyCMS->config->{'ccbill-check-access'}->{ subacc   };
    my $username = ShinyCMS->config->{'ccbill-check-access'}->{ username };
    my $password = ShinyCMS->config->{'ccbill-check-access'}->{ password };
    die 'CCBill details missing from config!' unless
        $account && $subacc && $username && $password;
    my $url = 'https://datalink.ccbill.com/data/main.cgi'.
                '?transactionTypes=ACTIVEMEMBERS'.
                '&clientAccnum='.$account.
                '&clientSubacc='.$subacc.
                '&username='.$username.
                '&password='.$password;
    $url .= '&testMode=1' if $testmode == 1;
    my $ua = LWP::UserAgent->new;
    my $response = $ua->get( $url );
    if ( $response->is_success ) {
        $csv_data = $response->decoded_content;
        open my $backup, '>', $Bin.'/'.$date.'.csv' or die "Failed to write backup CSV file: $!";
        print $backup $csv_data;
        close $backup or die "Failed to close backup CSV file: $!";
    }
    else {
        die $response->status_line;
    }
}
my @csv_lines = split "\n", $csv_data;

die $csv_lines[0] if $csv_lines[0] =~ m/Error: /;

# Loop through the CSV file building up a hash
my $csv = Text::CSV->new
    or die 'Failed to create CSV parser: ' . Text::CSV->error_diag;
my $active = {};
foreach my $csv_line ( @csv_lines ) {
    $csv->parse( $csv_line );
    my @line = $csv->fields;
    my $subscription_id = $line[3];
     my $renews_on = $line[22];
    my $duration  = $line[20];
    if ( $renews_on ) {
        my $new_dt = DateTime::Format::ISO8601->parse_datetime( $renews_on . 'T23:59:59' );
        $active->{ $subscription_id }->{ renews_on } = $new_dt;
        $active->{ $subscription_id }->{ duration  } = $duration;
    }
}


# Fetch the active user access list from the database
my $users = $schema->resultset('UserAccess')->search({
#    expires   => { '<=' => $now->add( days => 1 )->ymd },
    recurring => { '!=' => undef },
});

# Loop through active access list checking against CCBill active member list
my $e = 0;
my $a = 0;
my $r = 0;
while ( my $access = $users->next ) {
    my $subscription_id = $access->get_column('subscription_id') || '';
    if ( $subscription_id and not $active->{ $subscription_id } ) {
        print 'Access for ', $access->user->username, ' expired on ',
            $access->expires, "\n" if $debug;
        $access->update({ recurring => undef });
        $e++;
    }
    else {
        my $new_expiry = $active->{ $subscription_id }->{ renews_on };
        if ( $new_expiry->epoch == $access->expires->epoch ) {
            print 'Access for ', $access->user->username, ' unchanged; ',
                'access expires on ', $access->expires, "\n" if $debug;
            $a++
        }
        else {
            my $duration   = $active->{ $subscription_id }->{ duration  };
            print 'Access for ', $access->user->username, ' updated; ',
                ' old expiry date: ', $access->expires,
                ', new expiry date: ', $new_expiry, "\n" if $debug;
            $access->update({
                expires   => $new_expiry,
                recurring => $duration,
            });
            $r++;
        }
    }
}

print "RENEWED: $r    ACTIVE: $a    EXPIRED: $e\n" if $debug;

# Remove the PID file
$pidfile->remove;