neustar-ws_get_data 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +39 -0
- data/.rspec +4 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +21 -0
- data/LICENSE +20 -0
- data/README.md +48 -0
- data/Rakefile +34 -0
- data/lib/neustar-ws_get_data.rb +25 -0
- data/lib/neustar-ws_get_data/client.rb +115 -0
- data/lib/neustar-ws_get_data/elements/phone_attributes.rb +168 -0
- data/lib/neustar-ws_get_data/version.rb +6 -0
- data/neustar-ws_get_data.gemspec +30 -0
- data/spec/fixtures/fault.xml +12 -0
- data/spec/fixtures/improper_fault.xml +11 -0
- data/spec/fixtures/phone_attributes_success.xml +21 -0
- data/spec/lib/neustar-ws_get_data/client_spec.rb +139 -0
- data/spec/lib/neustar-ws_get_data/elements/phone_attributes_spec.rb +96 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/savon.rb +25 -0
- data/tmp/metric_fu/_data/20131021.yml +1028 -0
- data/tmp/metric_fu/_data/20131022.yml +969 -0
- metadata +160 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6d875a60812405cf6e3884324a776d0115fb7c17
|
4
|
+
data.tar.gz: fd7751d2ff95aff549a23d1f18272fe9dff93e0d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7545c58a95d222b7e2731cc35306362b716ebbf93fe54d090892a6870646995ef0eb8df9cccd5576e276dd98f464992b24678ca9ea0c4083c86e6c9825eaeb80
|
7
|
+
data.tar.gz: 9b97220f9ab3314b97aaa24f4cda7bc3fc65dc439a6d543a608b61882b99cff1d515055cb5845abf6f41a86a252cc974e27572549e27a520ad29825fd7a20a7a
|
data/.gitignore
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# SimpleCov generated
|
2
|
+
coverage
|
3
|
+
coverage.data
|
4
|
+
|
5
|
+
# rdoc generated
|
6
|
+
rdoc
|
7
|
+
|
8
|
+
# yard generated
|
9
|
+
doc
|
10
|
+
.yardoc
|
11
|
+
_yardoc
|
12
|
+
|
13
|
+
# bundler
|
14
|
+
.bundle
|
15
|
+
|
16
|
+
# jeweler generated
|
17
|
+
pkg
|
18
|
+
|
19
|
+
# For MacOS:
|
20
|
+
.DS_Store
|
21
|
+
|
22
|
+
# exclude everything in tmp
|
23
|
+
tmp/*
|
24
|
+
# except the metric_fu directory
|
25
|
+
!tmp/metric_fu/
|
26
|
+
# but exclude everything *in* the metric_fu directory
|
27
|
+
tmp/metric_fu/*
|
28
|
+
# except for the _data directory to track metrical outputs
|
29
|
+
!tmp/metric_fu/_data/
|
30
|
+
|
31
|
+
*.gem
|
32
|
+
*.rbc
|
33
|
+
.config
|
34
|
+
Gemfile.lock
|
35
|
+
InstalledFiles
|
36
|
+
lib/bundler/man
|
37
|
+
spec/reports
|
38
|
+
test/tmp
|
39
|
+
test/version_tmp
|
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
neustar-ws_get_data
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p247
|
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
gem 'savon', '~> 2.2'
|
4
|
+
|
5
|
+
group :development do
|
6
|
+
gem "yard"
|
7
|
+
gem "bundler"
|
8
|
+
end
|
9
|
+
|
10
|
+
group :development, :test do
|
11
|
+
gem "rspec", "~> 2.14.0"
|
12
|
+
gem 'rake', :require => false
|
13
|
+
|
14
|
+
# code metrics:
|
15
|
+
gem "metric_fu"
|
16
|
+
end
|
17
|
+
|
18
|
+
group :test do
|
19
|
+
gem 'simplecov' , :require => false
|
20
|
+
gem 'simplecov-rcov-text', :require => false
|
21
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 TMXCredit, author Zach Belzer
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Neustar::WsGetData
|
2
|
+
|
3
|
+
This gem wraps the SOAP interface for Neustar's WS-GetData Services. It
|
4
|
+
supports both interactive and batch queries.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'neustar-ws_get_data'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
gem install neustar-ws_get_data
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
client = Neustar::WsGetData::Client.new(
|
24
|
+
:username => 'username',
|
25
|
+
:password => 'password',
|
26
|
+
:service_id => 123456
|
27
|
+
)
|
28
|
+
|
29
|
+
client.operations
|
30
|
+
#=> [:query, :batch_query]
|
31
|
+
|
32
|
+
client.phone_attributes('8583145300', [:phone_type])
|
33
|
+
#=> {:phone_type => :wireless}
|
34
|
+
|
35
|
+
client.phone_attributes('8583145300')
|
36
|
+
#=> {:prepaid_phone => false,
|
37
|
+
:business_phone => :unknown,
|
38
|
+
:phone_in_service => "Active for 1 month or less",
|
39
|
+
:phone_type => :wireless}
|
40
|
+
```
|
41
|
+
|
42
|
+
## Contributing
|
43
|
+
|
44
|
+
1. Fork it
|
45
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
46
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
47
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
48
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'bundler'
|
6
|
+
require 'rake'
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
require './lib/neustar-ws_get_data/version'
|
9
|
+
|
10
|
+
begin
|
11
|
+
Bundler.setup(:default, :development)
|
12
|
+
rescue Bundler::BundlerError => e
|
13
|
+
$stderr.puts e.message
|
14
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
15
|
+
exit e.status_code
|
16
|
+
end
|
17
|
+
|
18
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
19
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
20
|
+
end
|
21
|
+
|
22
|
+
task :default => :spec
|
23
|
+
|
24
|
+
desc "Release tag for this version to github"
|
25
|
+
task "git:release" do
|
26
|
+
`git tag v#{Neustar::WsGetData::VERSION}`
|
27
|
+
`git push --tags`
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Build and push gem to rubygems"
|
31
|
+
task "build" do
|
32
|
+
`gem build neustar-ws_get_data.gemspec`
|
33
|
+
`gem push neustar-ws_get_data-#{Neustar::WsGetData::VERSION}.gem`
|
34
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
# Top-level namespace.
|
5
|
+
module Neustar
|
6
|
+
# Wrapper to interface with the WS-GetData Service.
|
7
|
+
module WsGetData
|
8
|
+
# Location of SOAP WSDL for WS-GetData:
|
9
|
+
WSDL = 'http://webapp.targusinfo.com/ws-getdata/query.asmx?WSDL'
|
10
|
+
end
|
11
|
+
|
12
|
+
# Top-level error class for Neustar.
|
13
|
+
class Error < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
# Error to be raised when basic configuration is missing.
|
17
|
+
class ConfigurationError < Error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
require File.expand_path("../neustar-ws_get_data/version", __FILE__)
|
22
|
+
require File.expand_path("../neustar-ws_get_data/client", __FILE__)
|
23
|
+
|
24
|
+
elements = File.expand_path("../neustar-ws_get_data/elements/*", __FILE__)
|
25
|
+
Dir[elements].each {|element| require element }
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Base client used to interface with WS-GetData query and batch_query services.
|
2
|
+
class Neustar::WsGetData::Client
|
3
|
+
# Maximum transaction ID:
|
4
|
+
MAX_TRANSACTION_ID = 1_000_000
|
5
|
+
|
6
|
+
# @param [Hash] options The configuration options
|
7
|
+
# @option options [String] :username Name of the Neustar account
|
8
|
+
# @option options [String] :password Password for the Neustar account
|
9
|
+
# @option options [String] ::service_id Service ID for the Neustar account
|
10
|
+
def initialize(options = {})
|
11
|
+
@service = Savon.client(:wsdl => Neustar::WsGetData::WSDL)
|
12
|
+
@username = options[:username] or
|
13
|
+
raise ConfigurationError, "Username required"
|
14
|
+
@password = options[:password] or
|
15
|
+
raise ConfigurationError, "Password required"
|
16
|
+
@service_id = options[:service_id] or
|
17
|
+
raise ConfigurationError, "Service ID required"
|
18
|
+
end
|
19
|
+
|
20
|
+
# List the operations available to the client.
|
21
|
+
#
|
22
|
+
# @return [Array<Symbol>]
|
23
|
+
def operations
|
24
|
+
@service.operations
|
25
|
+
end
|
26
|
+
|
27
|
+
# Execute an 'interactive' query.
|
28
|
+
#
|
29
|
+
# @param [Hash] params
|
30
|
+
# @return [Hash]
|
31
|
+
def query(params)
|
32
|
+
call(:query, params)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Execute a batch query.
|
36
|
+
#
|
37
|
+
# @param [Hash] params
|
38
|
+
# @return [Hash]
|
39
|
+
def batch_query(params)
|
40
|
+
call(:batch_query, params)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Execute a call to the given service type.
|
44
|
+
#
|
45
|
+
# @param [Symbol] service
|
46
|
+
# @return [Hash]
|
47
|
+
def call(service, params)
|
48
|
+
transaction_id = params.fetch(:transaction_id) { build_transaction_id }
|
49
|
+
|
50
|
+
message = origination_params.
|
51
|
+
merge(:transId => transaction_id).
|
52
|
+
merge(params)
|
53
|
+
|
54
|
+
begin
|
55
|
+
response = @service.call(service, :message => message)
|
56
|
+
process_response(service, response)
|
57
|
+
rescue Savon::SOAPFault => error
|
58
|
+
raise Neustar::Error, extract_fault_message(error)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Execute initial post-processing and error handling on the response.
|
63
|
+
#
|
64
|
+
# @param [Symbol] service
|
65
|
+
# @param [Savon::Response] response
|
66
|
+
#
|
67
|
+
# @return [Hash]
|
68
|
+
def process_response(service, response)
|
69
|
+
response_wrapper = response.body[:"#{service}_response"]
|
70
|
+
response_wrapper && response_wrapper[:response]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Helper to access PhoneAttributes element.
|
74
|
+
# TODO: Refactor out of here
|
75
|
+
#
|
76
|
+
# @param [#to_s] phone_number
|
77
|
+
# @param [Array<Symbol>] indicators
|
78
|
+
def phone_attributes(phone_number, indicators = [])
|
79
|
+
Neustar::WsGetData::PhoneAttributes.query(self, phone_number, indicators)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Parameters used to authenticate the client.
|
83
|
+
#
|
84
|
+
# @return [Hash]
|
85
|
+
def origination_params
|
86
|
+
{
|
87
|
+
:origination => {
|
88
|
+
:username => @username, :password => @password
|
89
|
+
},
|
90
|
+
:serviceId => @service_id.to_s
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns a unique transaction ID to send with each request.
|
95
|
+
#
|
96
|
+
# @return [String]
|
97
|
+
def build_transaction_id
|
98
|
+
SecureRandom.random_number(MAX_TRANSACTION_ID)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Pulls the error message from a Savon::SOAPFault exception.
|
102
|
+
#
|
103
|
+
# @param [Savon::SOAPFault] error
|
104
|
+
# @return [String]
|
105
|
+
def extract_fault_message(error)
|
106
|
+
data = error.to_hash
|
107
|
+
|
108
|
+
if (fault = data[:fault]) and (faultstring = fault[:faultstring]) then
|
109
|
+
faultstring
|
110
|
+
else
|
111
|
+
"Unknown Error"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
private :extract_fault_message
|
115
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# From the documentation:
|
2
|
+
#
|
3
|
+
# "Element ID 1320 accepts a phone number and returns attributes associated
|
4
|
+
# with the phone number. Currently, the following attributes are available:
|
5
|
+
# Prepaid Phone Indicator, Business Phone Indicator (BPI), Phone In-Service
|
6
|
+
# Indicator, and Phone Type Indicator."
|
7
|
+
module Neustar::WsGetData::PhoneAttributes
|
8
|
+
extend self
|
9
|
+
|
10
|
+
# Error raised when an invalid phone number is sent to the service.
|
11
|
+
class OutOfDomainError < Neustar::Error; end
|
12
|
+
|
13
|
+
# ID for "Phone Attributes".
|
14
|
+
ELEMENT_ID = 1320
|
15
|
+
|
16
|
+
# Service ID to specify the telephone number in a request.
|
17
|
+
TELEPHONE_SPECIFICATION_SERVICE_ID = 1
|
18
|
+
|
19
|
+
# Service ID to specify which attributes we want returned.
|
20
|
+
PHONE_ATTRIBUTES_REQUESTED_SERVICE_ID = 599
|
21
|
+
|
22
|
+
# Mappings to request certain indicators from the service.
|
23
|
+
INDICATORS = {
|
24
|
+
:prepaid_phone => 1,
|
25
|
+
:business_phone => 2,
|
26
|
+
:phone_in_service => 3,
|
27
|
+
:phone_type => 4,
|
28
|
+
}
|
29
|
+
|
30
|
+
# Whether or not a phone is prepaid.
|
31
|
+
PREPAID_PHONE_ATTRIBUTE_MAP = {
|
32
|
+
'Y' => true,
|
33
|
+
'N' => false
|
34
|
+
}
|
35
|
+
|
36
|
+
# The assumed purpose for a phone.
|
37
|
+
BUSINESS_PHONE_INDICATOR_MAP = {
|
38
|
+
'B' => :business_phone,
|
39
|
+
'C' => :residential_phone,
|
40
|
+
'D' => :dual_phone,
|
41
|
+
'U' => :unknown
|
42
|
+
}
|
43
|
+
|
44
|
+
# The Phone In-Service field indicates whether the phone is active and
|
45
|
+
# provides a range indicator for the active/inactive status.
|
46
|
+
PHONE_IN_SERVICE_INDICATOR_MAP = {
|
47
|
+
'A1' => "Active for 1 month or less",
|
48
|
+
'A2' => "Active for 2 months",
|
49
|
+
'A3' => "Active for 3 months",
|
50
|
+
'A4' => "Active for between 4-6 months",
|
51
|
+
'A5' => "Active for between 7-9 months",
|
52
|
+
'A6' => "Active for between 10-11 months",
|
53
|
+
'A7' => "Active for 12 months or longer",
|
54
|
+
'I1' => "Inactive for 1 month or less",
|
55
|
+
'I2' => "Inactive for 2 months",
|
56
|
+
'I3' => "Inactive for 3 months",
|
57
|
+
'I4' => "Inactive for between 4-6 months",
|
58
|
+
'I5' => "Inactive for between 7-9 months",
|
59
|
+
'I6' => "Inactive for between 10-11 months",
|
60
|
+
'I7' => "Inactive for 12 months or longer",
|
61
|
+
'U' => "Status Unknown",
|
62
|
+
}
|
63
|
+
|
64
|
+
# The type of phone used.
|
65
|
+
PHONE_TYPE_INDICATOR_MAP = {
|
66
|
+
'W' => :wireless,
|
67
|
+
'L' => :landline,
|
68
|
+
'U' => :unknown
|
69
|
+
}
|
70
|
+
|
71
|
+
# A map between each attribute and their possible values.
|
72
|
+
INDICATOR_MAPPINGS = {
|
73
|
+
:prepaid_phone => PREPAID_PHONE_ATTRIBUTE_MAP,
|
74
|
+
:business_phone => BUSINESS_PHONE_INDICATOR_MAP,
|
75
|
+
:phone_in_service => PHONE_IN_SERVICE_INDICATOR_MAP,
|
76
|
+
:phone_type => PHONE_TYPE_INDICATOR_MAP
|
77
|
+
}
|
78
|
+
|
79
|
+
# Indicates that an invalid phone number was sent to the service.
|
80
|
+
OUT_OF_DOMAIN_ERROR = "6"
|
81
|
+
|
82
|
+
# Method used to execute a query against the Phone Attributes element of the
|
83
|
+
# WS-GetData Service.
|
84
|
+
#
|
85
|
+
# @param [Neustar::WsGetData::Client] client
|
86
|
+
# @param [#to_s] phone_number
|
87
|
+
# @param [Array<Symbol>] indicators
|
88
|
+
#
|
89
|
+
# @return [Hash]
|
90
|
+
def query(client, phone_number, indicators = [])
|
91
|
+
indicators = parse_indicators(indicators)
|
92
|
+
|
93
|
+
params = {
|
94
|
+
:phone_number => phone_number,
|
95
|
+
:indicators => indicators
|
96
|
+
}
|
97
|
+
|
98
|
+
process_response(execute_request(client, params), params)
|
99
|
+
end
|
100
|
+
|
101
|
+
# Assemble and execute a query using the passed client.
|
102
|
+
#
|
103
|
+
# @param [Neustar::WsGetData::Client] client
|
104
|
+
# @param [Hash] params
|
105
|
+
# @option params [String] :phone_number
|
106
|
+
# @option params [String] :indicators
|
107
|
+
#
|
108
|
+
# @return [Hash]
|
109
|
+
def execute_request(client, params)
|
110
|
+
client.query(
|
111
|
+
:elements => { :id => ELEMENT_ID },
|
112
|
+
:serviceKeys => {
|
113
|
+
:serviceKey => [
|
114
|
+
{
|
115
|
+
:id => TELEPHONE_SPECIFICATION_SERVICE_ID,
|
116
|
+
:value => params[:phone_number]
|
117
|
+
},
|
118
|
+
{
|
119
|
+
:id => PHONE_ATTRIBUTES_REQUESTED_SERVICE_ID,
|
120
|
+
:value => params[:indicators]
|
121
|
+
}
|
122
|
+
]
|
123
|
+
}
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Do element specific processing on response from client.
|
128
|
+
#
|
129
|
+
# @param [Hash] response
|
130
|
+
# @option response [String] :error_code The stringified number
|
131
|
+
# of the error code
|
132
|
+
# @option response [Hash] :result
|
133
|
+
# @param [Hash] params
|
134
|
+
# @option params [String] :phone_number
|
135
|
+
#
|
136
|
+
# @return [Hash]
|
137
|
+
def process_response(response, params)
|
138
|
+
if response[:error_code] == OUT_OF_DOMAIN_ERROR
|
139
|
+
raise OutOfDomainError, params[:phone_number]
|
140
|
+
else
|
141
|
+
string = response[:result][:element][:value]
|
142
|
+
result = {}
|
143
|
+
|
144
|
+
INDICATOR_MAPPINGS.each do |name, mapping|
|
145
|
+
mapping.detect do |key, value|
|
146
|
+
result[name] = value if string.index(key)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
result
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Given a list of indicator symbols, derive the argument to send the service.
|
155
|
+
#
|
156
|
+
# @param [Array<Symbol>] indicators
|
157
|
+
# @return [String]
|
158
|
+
def parse_indicators(indicators)
|
159
|
+
vals =
|
160
|
+
if indicators.empty?
|
161
|
+
INDICATORS.values
|
162
|
+
else
|
163
|
+
INDICATORS.values_at(*indicators)
|
164
|
+
end
|
165
|
+
|
166
|
+
vals.join(',')
|
167
|
+
end
|
168
|
+
end
|