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 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