neustar-ws_get_data 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format nested
3
+ --order rand
4
+ --profile
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