smart-mobile 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.DS_Store ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ # YARD artifacts
16
+ .yardoc
17
+ _yardoc
18
+ doc/
19
+ cert/
20
+ test/*.yml
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem "rake"
4
+ # Specify your gem's dependencies in textile_editor_helper.gemspec
5
+ gemspec
data/README.md ADDED
@@ -0,0 +1,12 @@
1
+ smart-mobile
2
+ ============
3
+
4
+ Smart Mobile API
5
+
6
+ ## MIT Open Source License
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
11
+
12
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake/testtask'
2
+
3
+ Rake::TestTask.new do |t|
4
+ t.libs << 'test'
5
+ end
6
+
7
+ desc "Run tests"
8
+ task :default => :test
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+
3
+ require 'nokogiri'
4
+ require 'net/https'
5
+ require 'uri'
6
+ require 'json'
7
+
8
+ require_relative 'smart/support'
9
+ require_relative 'smart/version'
10
+ require_relative 'smart/rest/config'
11
+ require_relative 'smart/rest/response'
12
+ require_relative 'smart/rest/client'
13
+ require_relative 'smart/rest/sms'
@@ -0,0 +1,81 @@
1
+ module Smart
2
+ module REST
3
+ class Client
4
+ include ClassSupportMixin
5
+ include Smart::REST::Configuration
6
+
7
+ HTTP_HEADERS = {
8
+ 'Content-Type' => 'application/json',
9
+ 'Accept' => 'application/json',
10
+ 'Authorization' => 'WSSE realm="SDP",profile="UsernameToken"'
11
+ }
12
+
13
+ set_attributes :host => 'npwifi.smart.com.ph',
14
+ :port => 443,
15
+ :timeout => 30,
16
+ :retry_limit => 1,
17
+ :sp_id => '',
18
+ :sp_password => '',
19
+ :service_id => '',
20
+ :nonce => '',
21
+ :creation_time => '',
22
+ :trans_id => '',
23
+ :access_code => '',
24
+ :mobile_number => '',
25
+ :path_to_cert => '',
26
+ :mobile_number => '',
27
+ :message => ''
28
+
29
+
30
+ attr_reader :sp_id, :sp_password, :sp_service_id, :nonce, :creation_time, :trans_id, :access_code, :mobile_number, :path_to_cert
31
+
32
+ def headers
33
+ HTTP_HEADERS.merge! ({
34
+ 'X-WSSE' => %{ "UsernameToken Username="#{self.sp_id}",PasswordDigest="#{self.sp_password}",Nonce="#{self.nonce}", Created="#{self.creation_time}"},
35
+ 'X-RequestHeader' => %{ "request TransId="",ServiceId="#{self.service_id}" }
36
+ })
37
+ end
38
+
39
+ def send_sms(args = {})
40
+ request = setup_connection(args)
41
+ response = connect(request)
42
+ end
43
+
44
+ private
45
+
46
+ def setup_sms_outbound_endpoint
47
+ "https://#{self.host}/1/smsmessaging/outbound/#{self.access_code}/requests"
48
+ end
49
+
50
+ def setup_connection(args)
51
+ uri = URI.parse(setup_sms_outbound_endpoint)
52
+ @http = Net::HTTP.new(uri.host, uri.port)
53
+ @http.use_ssl = true
54
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
55
+ @http.open_timeout = 3 # in seconds
56
+ @http.read_timeout = 3 # in seconds
57
+
58
+ store = OpenSSL::X509::Store.new
59
+ store.add_cert(OpenSSL::X509::Certificate.new(File.read(self.path_to_cert)))
60
+ @http.cert_store = store
61
+
62
+ request = Net::HTTP::Post.new(uri.request_uri, initheader = headers)
63
+ request.body = args.to_json
64
+ request
65
+ end
66
+
67
+ def connect(request)
68
+ response = @http.request(request)
69
+
70
+ if response.body and !response.body.empty?
71
+ object = JSON.parse(response.body)
72
+ end
73
+ if response.kind_of? Net::HTTPClientError
74
+ error = Smart::REST::Response.new(object["requestError"]["serviceException"]["messageId"])
75
+ raise error.to_s
76
+ end
77
+ response
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,22 @@
1
+ module Smart
2
+ module REST
3
+ module Configuration
4
+ def self.included(base)
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ def configure(&block)
10
+ config = self.new
11
+ raise ArgumentError, "Please provide configuration block" unless block_given?
12
+ yield config
13
+
14
+ [:sp_id, :sp_password, :service_id, :access_code, :path_to_cert].each do |required|
15
+ raise "#{required} is required" unless config.send(required)
16
+ end
17
+ config
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,95 @@
1
+ module Smart
2
+ module REST
3
+ class Response
4
+ attr_reader :response_code
5
+ #TODO:
6
+ # Service Exception Extension
7
+ # Policy Exceptions
8
+ # Policy Exception Extension
9
+ @@error_map = {
10
+ :condition_not_met? => 304,
11
+ :invalid_request_parameters? => 400,
12
+ :authentication_failed? => 401,
13
+ :not_permitted? => 403,
14
+ :not_found? => 404,
15
+ :method_not_allowed? => 405,
16
+ :conflict? => 409,
17
+ :content_length_required? => 411,
18
+ :precondition_failed? => 412,
19
+ :request_body_too_large? => 413,
20
+ :invalid_range? => 416,
21
+ :internal_server_error? => 500,
22
+ :server_busy? => 503,
23
+ :service_error? => 'SVC0001',
24
+ :invalid_input_value? => 'SVC0002',
25
+ :invalid_input_value_with_valid_values? => 'SVC0003',
26
+ :no_valid_address? => 'SVC0004',
27
+ :duplicate_correlator? => 'SVC0005',
28
+ :invalid_group? => 'SVC0006',
29
+ :invalid_charging_info? => 'SVC0007',
30
+ :overlapping_criteria? => 'SVC0008',
31
+ :success? => 200,
32
+ :created? => 201,
33
+ :no_content? => 204,
34
+ :password_not_accepted? => 'SVC0901'
35
+ }
36
+
37
+ @@status_messages = {
38
+ 304 => "ConditionNotMet - Not Modified: The condition specified in the conditional header(s) was not met for a read operation.",
39
+ 400 => "Invalid parameters in the request",
40
+ 401 => "Authentication failure",
41
+ 403 => "Application does not have permissions to access resource due to the policy constraints (request rate limit, etc)",
42
+ 404 => "Not Found - The specified resource does not exist.",
43
+ 405 => "Method not allowed by the resource",
44
+ 409 => "Conflict",
45
+ 411 => "Length Required: The Content-Length header was not specified.",
46
+ 412 => "Precondition Failed: The condition specified in the conditional header(s) was not met for a write operation.",
47
+ 413 => "RequestBodyTooLarge - Request Entity Too Large: The size of the request body exceeds the maximum size permitted.",
48
+ 416 => "InvalidRange - Requested Range Not Satisfiable: The range specified is invalid for the current size of the resource.",
49
+ 500 => "Internal server error",
50
+ 503 => "ServerBusy - Service Unavailable: The server is currently unable to receive requests. Please retry your request.",
51
+ "SVC0001" => "Service Error",
52
+ "SVC0002" => "Invalid input value",
53
+ "SVC0003" => "Invalid input value with list of valid values",
54
+ "SVC0004" => "No valid addresses",
55
+ "SVC0005" => "Duplicate correlator",
56
+ "SVC0006" => "Invalid group",
57
+ "SVC0007" => "Invalid charging information",
58
+ "SVC0008" => "Overlapping Criteria",
59
+ "SVC0901" => "Sp password is not accepted!",
60
+ 200 => "Success",
61
+ 201 => "Created",
62
+ 204 => "No Content"
63
+ }
64
+
65
+ def initialize(code)
66
+ @response_code = code
67
+ end
68
+
69
+ def valid?
70
+ [200, 201].include?(self.response_code)
71
+ end
72
+
73
+ def to_s
74
+ #"#{self.response_code} - #{msg}"
75
+ msg
76
+ end
77
+
78
+ def msg(code = self.response_code)
79
+ if msg = @@status_messages[code]
80
+ msg
81
+ else
82
+ raise ArgumentError, "#{code} - undefined response code"
83
+ end
84
+ end
85
+
86
+ def method_missing(method_id)
87
+ if code = @@error_map[method_id.to_sym]
88
+ self.response_code == code
89
+ else
90
+ raise NoMethodError
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,8 @@
1
+ module Smart
2
+ module REST
3
+ class SMS
4
+ include ClassSupportMixin
5
+ set_attributes :mobile_number => nil, :message => nil, :access_code => nil
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,30 @@
1
+ module ClassSupportMixin
2
+ def self.included(base)
3
+ base.send(:include, InstanceMethods)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ module ClassMethods
8
+ def set_attributes(attrs)
9
+ attr_accessor *attrs.keys
10
+ define_method(:default_attributes) { attrs }
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+ def initialize(options={})
16
+ init = if self.respond_to?(:default_attributes)
17
+ self.default_attributes.merge(options)
18
+ else
19
+ options
20
+ end
21
+ init.each { |k, v| self.send("#{k}=", v) if self.respond_to?(k) }
22
+ end
23
+
24
+ def attributes
25
+ attrs = {}
26
+ self.default_attributes.keys.each {|k| attrs[k] = self.send(k) if self.respond_to?(k)}
27
+ attrs
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ module Smart
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'smart-mobile'
6
+ s.version = '0.0.1'
7
+ s.date = '2012-11-24'
8
+ s.email = 'me@iantusil.com'
9
+
10
+ s.summary = "A gem for consuming Smart Mobile API"
11
+ s.description = "A gem for consuming Smart Mobile API (currently supports SMS only)."
12
+ s.author = "Ian Bert Tusil"
13
+ s.homepage = 'http://www.smart.com.ph/developer'
14
+ s.license = 'MIT'
15
+
16
+ s.platform = Gem::Platform::RUBY
17
+ s.require_paths = %w[lib]
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = Dir['test/*.rb']
20
+
21
+ s.add_development_dependency 'minitest', '~> 4.3.3'
22
+ end
data/test/.DS_Store ADDED
Binary file
@@ -0,0 +1,9 @@
1
+ require 'yaml'
2
+ require 'minitest/pride'
3
+ require 'minitest/autorun'
4
+ require 'minitest/spec'
5
+ require 'minitest/matchers'
6
+
7
+ def config_file
8
+ config ||= YAML::load(File.open((File.join(File.dirname(__FILE__), 'config.yml'))))
9
+ end
@@ -0,0 +1,52 @@
1
+ require_relative 'test_helper'
2
+ require_relative '../lib/smart-mobile'
3
+
4
+ describe Smart do
5
+
6
+ before do
7
+ @sms = Smart::REST::SMS.new
8
+ end
9
+
10
+ def valid_sms_data
11
+ {"outboundSMSMessageRequest" =>
12
+ {"address" => ["tel:+639176230655"],
13
+ "senderAddress" => config_file['access_code'].to_s,
14
+ "outboundSMSTextMessage" => {
15
+ "message" => "Test Message"
16
+ }
17
+ }
18
+ }
19
+ end
20
+
21
+ def client
22
+ @client ||= initialize_rest_client
23
+ end
24
+
25
+ def initialize_rest_client
26
+ Smart::REST::Client.configure do |config|
27
+ config.sp_id = config_file['sp_id']
28
+ config.sp_password = config_file['sp_password'].to_s
29
+ config.service_id = config_file['service_id']
30
+ config.access_code = config_file['access_code'].to_s
31
+ config.path_to_cert = config_file['path_to_cert']
32
+ config.creation_time = config_file['creation_time']
33
+ config.nonce = config_file['nonce']
34
+ end
35
+ end
36
+
37
+ it 'should not allow for invalid sp_password' do
38
+ begin
39
+ response = client.send_sms(valid_sms_data)
40
+ rescue Exception => e
41
+ e.message.must_equal Smart::REST::Response.new('SVC0901').to_s
42
+ end
43
+ end
44
+
45
+ it 'should have a valid certificate' do
46
+
47
+ end
48
+
49
+ it 'should try to retry up to the max number of retry limited' do
50
+ end
51
+
52
+ end
data/travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smart-mobile
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ian Bert Tusil
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-24 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitest
16
+ requirement: &319130 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 4.3.3
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *319130
25
+ description: A gem for consuming Smart Mobile API (currently supports SMS only).
26
+ email: me@iantusil.com
27
+ executables: []
28
+ extensions: []
29
+ extra_rdoc_files: []
30
+ files:
31
+ - .DS_Store
32
+ - .gitignore
33
+ - Gemfile
34
+ - README.md
35
+ - Rakefile
36
+ - lib/smart-mobile.rb
37
+ - lib/smart/rest/client.rb
38
+ - lib/smart/rest/config.rb
39
+ - lib/smart/rest/response.rb
40
+ - lib/smart/rest/sms.rb
41
+ - lib/smart/support.rb
42
+ - lib/smart/version.rb
43
+ - smart-mobile.gemspec
44
+ - test/.DS_Store
45
+ - test/test_helper.rb
46
+ - test/test_smart.rb
47
+ - travis.yml
48
+ homepage: http://www.smart.com.ph/developer
49
+ licenses:
50
+ - MIT
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ! '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubyforge_project:
69
+ rubygems_version: 1.8.17
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: A gem for consuming Smart Mobile API
73
+ test_files:
74
+ - test/test_helper.rb
75
+ - test/test_smart.rb