From 1d339ad33855e8df8c1f466b494acbfd0e0907da Mon Sep 17 00:00:00 2001 From: Ivan Kohler Date: Wed, 12 Dec 2012 16:31:06 -0800 Subject: [PATCH] initial commit --- Changes | 14 +++ MANIFEST | 13 +++ MYMETA.yml | 26 +++++ Makefile.PL | 19 ++++ README | 56 ++++++++++ lib/Net/VoIP_Innovations.pm | 252 ++++++++++++++++++++++++++++++++++++++++++++ pm_to_blib | 0 t/00-load.t | 9 ++ t/01-login.t | 17 +++ t/41-auditDIDs.t | 53 ++++++++++ t/61-getDID.t | 28 +++++ t/62-getDIDs.t | 34 ++++++ t/lib/test_account.pl | 29 +++++ t/pod-coverage.t | 18 ++++ t/pod.t | 12 +++ 15 files changed, 580 insertions(+) create mode 100644 Changes create mode 100644 MANIFEST create mode 100644 MYMETA.yml create mode 100644 Makefile.PL create mode 100644 README create mode 100644 lib/Net/VoIP_Innovations.pm create mode 100644 pm_to_blib create mode 100644 t/00-load.t create mode 100644 t/01-login.t create mode 100644 t/41-auditDIDs.t create mode 100644 t/61-getDID.t create mode 100644 t/62-getDIDs.t create mode 100644 t/lib/test_account.pl create mode 100644 t/pod-coverage.t create mode 100644 t/pod.t diff --git a/Changes b/Changes new file mode 100644 index 0000000..95c439c --- /dev/null +++ b/Changes @@ -0,0 +1,14 @@ +Revision history for Net-VoIP_Innovations + +2.00 unreleased + - update for VoIP Innovations API 2.0, rename to Net::VoIP_Innovations + +0.03 unreleased + - test updates, turn down debugging verbosity + +0.02 unreleased + - update for Net::HTTPS::Any 0.10 without HTTP in response code + +0.01 unreleased + First version, (not) released on an unsuspecting world. + diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..60ec711 --- /dev/null +++ b/MANIFEST @@ -0,0 +1,13 @@ +Changes +MANIFEST +Makefile.PL +README +lib/Net/VoIP_Innovations.pm +t/00-load.t +t/01-login.t +t/41-auditDIDs.t +t/61-getDID.t +t/62-getDIDs.t +t/pod-coverage.t +t/pod.t +t/lib/test_account.pl diff --git a/MYMETA.yml b/MYMETA.yml new file mode 100644 index 0000000..b1501c1 --- /dev/null +++ b/MYMETA.yml @@ -0,0 +1,26 @@ +--- +abstract: 'Interface to VoIP_Innovations API' +author: + - 'Ivan Kohler ' +build_requires: + ExtUtils::MakeMaker: 0 +configure_requires: + ExtUtils::MakeMaker: 0 +distribution_type: module +dynamic_config: 0 +generated_by: 'ExtUtils::MakeMaker version 6.57_05' +license: unknown +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: 1.4 +name: Net-VoIP_Innovations +no_index: + directory: + - t + - inc +requires: + Net::HTTPS::Any: 0.1 + Test::More: 0 + XML::Simple: 0 + XML::Writer: 0 +version: 2.00 diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..74049bb --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,19 @@ +use strict; +use warnings; +use ExtUtils::MakeMaker; + +WriteMakefile( + NAME => 'Net::VoIP_Innovations', + AUTHOR => 'Ivan Kohler ', + VERSION_FROM => 'lib/Net/VoIP_Innovations.pm', + ABSTRACT_FROM => 'lib/Net/VoIP_Innovations.pm', + PL_FILES => {}, + PREREQ_PM => { + 'Test::More' => 0, + 'XML::Simple' => 0, + 'XML::Writer' => 0, + 'Net::HTTPS::Any' => 0.10 + }, + dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', }, + clean => { FILES => 'Net-VoIP_Innovations-*' }, +); diff --git a/README b/README new file mode 100644 index 0000000..0f64da5 --- /dev/null +++ b/README @@ -0,0 +1,56 @@ +Net-VoIP_Innovations + +This is an interface to the VoIP Innovations (formerly GlobalPOPs) API for +wholesale DID (phone number) provisioning. It is only useful if you have an +account with GlobalPOPs wholesale VoIP service. + + +INSTALLATION + +To install this module, run the following commands: + + perl Makefile.PL + make + make test + make install + + +SUPPORT AND DOCUMENTATION + +After installing, you can find documentation for this module with the +perldoc command. + + perldoc Net::VoIP_Innovations + +You can also look for information at: + + RT, CPAN's request tracker + http://rt.cpan.org/NoAuth/Bugs.html?Dist=Net-VoIP_Innovations + + AnnoCPAN, Annotated CPAN documentation + http://annocpan.org/dist/Net-VoIP_Innovations + + CPAN Ratings + http://cpanratings.perl.org/d/Net-VoIP_Innovations + + Search CPAN + http://search.cpan.org/dist/Net-VoIP_Innovations + + +COPYRIGHT AND LICENCE + +Copyright (C) 2008 Freeside Internet Services, Inc. (http://freeside.biz/) + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + + +ADVERTISEMENT + +Need a complete, open-source back-office and customer self-service solution? +The Freeside software includes support for VoIP Innovations integration, CDR +rating, invoicing, credit card and electronic check processing, integrated +trouble ticketing, and customer signup and self-service web interfaces. + +http://freeside.biz/freeside/ + diff --git a/lib/Net/VoIP_Innovations.pm b/lib/Net/VoIP_Innovations.pm new file mode 100644 index 0000000..bd56c8b --- /dev/null +++ b/lib/Net/VoIP_Innovations.pm @@ -0,0 +1,252 @@ +package Net::VoIP_Innovations; + +use warnings; +use strict; +use Data::Dumper; +use XML::Simple; +use XML::Writer; +use Net::HTTPS::Any qw( 0.10 https_post ); + +=head1 NAME + +Net::VoIP_Innovations - Interface to VoIP_Innovations API + +=cut + +our $VERSION = '2.00'; +our $URL = 'https://www.loginto.us/VOIP/api2.pl'; +#could be parsed from URL, if it mattered... +our $HOST = 'www.loginto.us'; +our $PATH = '/VOIP/api2.pl'; +our $PORT = 443; #to allow testing to override + +our $AUTOLOAD; +our $errstr = ''; + +=head1 SYNOPSIS + + use Net::VoIP_Innovations; + + my $handle = Net::VoIP_Innovations->new( + 'login' => 'tofu', + 'password' => 'beast', + 'debug' => 1, + ); + + #DID functions + #auditDIDs + #queryDID + #reserveDID + #assignDID + #configDID + #releaseDID + + #911 Functions + + #Locator Functions + + ... + +=head1 METHODS + +=head2 new HASHREF | OPTION, VALUE ... + +Creates a new Net::VoIP_Innovations object. Options may be passed +as a hash reference or a flat list of names and values. + +=over 4 + +=item login (required) + +=item password (required) + +=item login (required) + +=back + +=cut + +# If there is an error, +#returns false and sets an error string which may be queried with the I +#class method. + +sub new { + my $proto = shift; + my $class = ref($proto) || $proto; + my $self = ref($_[0]) ? shift : { @_ }; + $self->{'debug'} ||= 0; + bless($self, $class); +} + +=head2 errstr + +=cut + +sub errstr { + my $class = shift; + + return $errstr + unless ref($class) && $class->isa('Net::VoIP_Innovations'); + + my $self = $class; + $self->{errstr}; +} + +sub DESTROY { }; # no-op + +sub AUTOLOAD { + my $self = shift; + my $opts = ref($_[0]) ? shift : { @_ }; + + $AUTOLOAD =~ /(^|::)(\w+)$/ or die "unparsable AUTOLOAD: $AUTOLOAD"; + my $function = $2; + + my $output; + my $w = new XML::Writer(OUTPUT => \$output, DATA_MODE => 1, DATA_INDENT => 3); + + $w->xmlDecl('ISO-8859-1'); + $w->doctype('request', undef, $URL); + + $w->startTag('request', 'id' => ''); #XXX request ID??? + $w->startTag('header'); + $w->startTag('sender'); + + if ( $self->{'sessionid'} ) { + + #$w->dataElement( 'login' => '' ); + #$w->dataElement( 'password' => '' ); + $w->dataElement( 'sessionid' => $self->{'sessionid'} ); + + } else { + + $w->dataElement( 'login' => $self->{'login'} ); + $w->dataElement( 'password' => $self->{'password'} ); + #$w->dataElement( 'sessionid' => '' ); + + } + + $w->endTag('sender'); + $w->endTag('header'); + + $w->startTag('body'); + + $w->dataElement( 'requesttype' => $function ); + + if ( keys %$opts ) { + $w->startTag('item'); + foreach my $opt ( keys %$opts ) { + $w->dataElement( $opt => $opts->{$opt} ); + } + $w->endTag('item'); + } + + $w->endTag('body'); + + $w->endTag('request'); + + #$output =~ s/\n+/\n/g; + + warn "XML Request for $function function:\n$output" + if $self->{'debug'} > 1; + + my( $page, $response, %reply_headers ) = https_post( + 'host' => $HOST, + 'port' => $PORT, + 'path' => ($PATH||443), + 'args' => { 'apidata' => $output, }, + #'content' => $output, + #'Content-Type' => 'text/plain', + #'Content-Type' => 'text/xml', + 'Content-Type' => 'application/xml', + #'headers' => {}, + 'debug' => ( $self->{'debug'} > 1 ? 1 : 0 ), + ); + + unless ( $response =~ /^200/i ) { + $self->{'errstr'} = $response; + return ''; + } + + warn "XML Response for $function function:\n: $page" + if $self->{'debug'} > 1; + + my $hashref = XMLin( $page ); + + warn "Parsed response for $function funtion:\n". Dumper($hashref) + if $self->{'debug'} > 1; + + my $return = $hashref->{'body'}; + + warn "Returning data:\n". Dumper($return) + if $self->{'debug'} > 1; + + $return; + +} + +=head1 AUTHOR + +Ivan Kohler, C<< >> + +=head1 BUGS + +Please report any bugs or feature requests to C, or through +the web interface at L. I will be notified, and then you'll +automatically be notified of progress on your bug as I make changes. + + + + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc Net::VoIP_Innovations + + +You can also look for information at: + +=over 4 + +=item * RT: CPAN's request tracker + +L + +=item * AnnoCPAN: Annotated CPAN documentation + +L + +=item * CPAN Ratings + +L + +=item * Search CPAN + +L + +=back + + +=head1 ACKNOWLEDGEMENTS + + +=head1 COPYRIGHT & LICENSE + +Copyright 2008-2012 Freeside Internet Services, Inc. (http://freeside.biz/) + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + + +=head1 ADVERTISEMENT + +Need a complete, open-source back-office and customer self-service solution? +The Freeside software includes support for VoIP Innovations integration, CDR +rating, invoicing, credit card and electronic check processing, integrated +trouble ticketing, and customer signup and self-service web interfaces. + +http://freeside.biz/freeside/ + +=cut + +1; # End of Net::VoIP_Innovations diff --git a/pm_to_blib b/pm_to_blib new file mode 100644 index 0000000..e69de29 diff --git a/t/00-load.t b/t/00-load.t new file mode 100644 index 0000000..ddd413c --- /dev/null +++ b/t/00-load.t @@ -0,0 +1,9 @@ +#!perl -T + +use Test::More tests => 1; + +BEGIN { + use_ok( 'Net::VoIP_Innovations' ); +} + +diag( "Testing Net::VoIP_Innovations $Net::VoIP_Innovations::VERSION, Perl $], $^X" ); diff --git a/t/01-login.t b/t/01-login.t new file mode 100644 index 0000000..2642b59 --- /dev/null +++ b/t/01-login.t @@ -0,0 +1,17 @@ +#!/usr/bin/perl -w + +use Test::More; +require 't/lib/test_account.pl'; + +my($login, $password) = test_account_or_skip; +plan tests => 2; + +use_ok 'Net::VoIP_Innovations'; + +my $gp = Net::VoIP_Innovations->new('login' => $login, + 'password' => $password ); + +#eww. what is the right, TEST_VERBOSE-aware way to do this +warn Net::VoIP_Innovations->errstr unless $gp; + +ok( $gp, 'Login sucessful' ); diff --git a/t/41-auditDIDs.t b/t/41-auditDIDs.t new file mode 100644 index 0000000..6793931 --- /dev/null +++ b/t/41-auditDIDs.t @@ -0,0 +1,53 @@ +#!/usr/bin/perl -w + +use Test::More skip_all => "not working with current test account?"; + +require 't/lib/test_account.pl'; +require Net::VoIP_Innovations; + +my($login, $password) = test_account_or_skip(); +plan tests => 3; + +my $debug = $ENV{TEST_VERBOSE}; + +my $gp = Net::VoIP_Innovations->new( 'login' => $login, + 'password' => $password, + #'debug' => $debug, + ); +my $return = $gp->auditDIDs(); + +use Data::Dumper; +diag( Dumper($return) ); # if $debug; + +ok( $return, 'auditDIDs returned something' ); + +# 'did' => [ +# { +# 'statuscode' => '100', +# 'status' => 'Number currently assigned to you with refid rewritten as \'\' to endpoint 521', +# 'cnam' => 'False', +# 'expire_seconds' => {}, +# 'availability' => 'assigned', +# 'tn' => '2137851430', +# 'rewrite' => {}, +# 'endpoint' => '521', +# 'refid' => {} +# }, +# { +# 'statuscode' => '100', +# 'status' => 'Number currently assigned to you with refid rewritten as \'\' to endpoint 521', +# 'cnam' => 'False', +# 'expire_seconds' => {}, +# 'availability' => 'assigned', +# 'tn' => '5109626974', +# 'rewrite' => {}, +# 'endpoint' => '521', +# 'refid' => {} +# } +# ] + + +ok( $return->{'did'}, 'auditDIDs returned did data' ); + +ok( ref($return->{'did'}) eq 'ARRAY', 'auditDIDs did data is a list' ); + diff --git a/t/61-getDID.t b/t/61-getDID.t new file mode 100644 index 0000000..15dfe54 --- /dev/null +++ b/t/61-getDID.t @@ -0,0 +1,28 @@ +#!/usr/bin/perl -w + +#BEGIN { +# $Net::HTTPS::Any::skip_NetSSLeay = 1; +# $Net::HTTPS::Any::skip_NetSSLeay = 1; +#} + +use Test::More; + +require 't/lib/test_account.pl'; +require Net::VoIP_Innovations; + +my($login, $password) = test_account_or_skip(); +plan tests => 1; + +my $debug = $ENV{TEST_VERBOSE}; + +my $gp = Net::VoIP_Innovations->new( 'login' => $login, + 'password' => $password, + #'debug' => $debug, + ); +my $return = $gp->getDID(); + +use Data::Dumper; +diag( Dumper($return) ) if $debug; + +#XXX test some things about the return... +ok( $return, 'getDID returned something' ); diff --git a/t/62-getDIDs.t b/t/62-getDIDs.t new file mode 100644 index 0000000..52f0170 --- /dev/null +++ b/t/62-getDIDs.t @@ -0,0 +1,34 @@ +#!/usr/bin/perl -w + +#BEGIN { +# $Net::HTTPS::Any::skip_NetSSLeay = 1; +# $Net::HTTPS::Any::skip_NetSSLeay = 1; +#} + +use Test::More; + +require 't/lib/test_account.pl'; +require Net::VoIP_Innovations; + +my($login, $password) = test_account_or_skip(); +plan tests => 1; + + +my $debug = $ENV{TEST_VERBOSE}; + +my $gp = Net::VoIP_Innovations->new( 'login' => $login, + 'password' => $password, + #'debug' => $debug, + ); +my $return = $gp->getDIDs( + 'state' => 'CA', + 'lata' => '722', + #'npa' => '415', + 'orderby' => 'ORDER BY npa', #? +); + +use Data::Dumper; +diag( Dumper($return) ); # if $debug; + +#XXX test some things about the return... +ok( $return, 'getDIDs returned something' ); diff --git a/t/lib/test_account.pl b/t/lib/test_account.pl new file mode 100644 index 0000000..c52067d --- /dev/null +++ b/t/lib/test_account.pl @@ -0,0 +1,29 @@ +use Test::More; + +sub test_account_or_skip { + my($login, $password) = test_account(); + + unless( defined $login ) { + plan skip_all => "No test account"; + } + + return($login, $password); +} + +sub test_account { + open TEST_ACCOUNT, "t/test_account" or return; + my($login, $password, $hostport) = ; + chomp $login; + chomp $password; + chomp $hostport; + + if ( $hostport =~ /^\s*([\w\.]+)(:(\d+))?\s*$/ ) { + my($host, $port) = ($1, $3); + $Net::VoIP_Innovations::HOST = $host; + $Net::VoIP_Innovations::PORT = $port; + } + + return($login, $password); +} + +1; diff --git a/t/pod-coverage.t b/t/pod-coverage.t new file mode 100644 index 0000000..fc40a57 --- /dev/null +++ b/t/pod-coverage.t @@ -0,0 +1,18 @@ +use strict; +use warnings; +use Test::More; + +# Ensure a recent version of Test::Pod::Coverage +my $min_tpc = 1.08; +eval "use Test::Pod::Coverage $min_tpc"; +plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage" + if $@; + +# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version, +# but older versions don't recognize some common documentation styles +my $min_pc = 0.18; +eval "use Pod::Coverage $min_pc"; +plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage" + if $@; + +all_pod_coverage_ok(); diff --git a/t/pod.t b/t/pod.t new file mode 100644 index 0000000..ee8b18a --- /dev/null +++ b/t/pod.t @@ -0,0 +1,12 @@ +#!perl -T + +use strict; +use warnings; +use Test::More; + +# Ensure a recent version of Test::Pod +my $min_tp = 1.22; +eval "use Test::Pod $min_tp"; +plan skip_all => "Test::Pod $min_tp required for testing POD" if $@; + +all_pod_files_ok(); -- 2.11.0