singtel_sdp 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +134 -0
  4. data/Rakefile +27 -0
  5. data/app/assets/stylesheets/application.css +0 -0
  6. data/app/controllers/singtel_sdp/base_adapter_controller.rb +64 -0
  7. data/app/models/singtel_sdp/base_adapter.rb +400 -0
  8. data/app/models/singtel_sdp/return_code.rb +113 -0
  9. data/app/views/singtel_sdp/base_adapter/create_customer_response.xml.builder +9 -0
  10. data/app/views/singtel_sdp/base_adapter/create_product_response.xml.builder +9 -0
  11. data/app/views/singtel_sdp/base_adapter/create_user_response.xml.builder +9 -0
  12. data/app/views/singtel_sdp/base_adapter/delete_customer_response.xml.builder +6 -0
  13. data/app/views/singtel_sdp/base_adapter/delete_product_response.xml.builder +6 -0
  14. data/app/views/singtel_sdp/base_adapter/delete_user_response.xml.builder +6 -0
  15. data/app/views/singtel_sdp/base_adapter/error_response.xml.builder +7 -0
  16. data/app/views/singtel_sdp/base_adapter/invalid_session.html.haml +1 -0
  17. data/app/views/singtel_sdp/base_adapter/select_customer_response.xml.builder +11 -0
  18. data/app/views/singtel_sdp/base_adapter/update_customer_response.xml.builder +6 -0
  19. data/app/views/singtel_sdp/base_adapter/update_product_response.xml.builder +9 -0
  20. data/app/views/singtel_sdp/base_adapter/update_user_response.xml.builder +6 -0
  21. data/config/routes.rb +2 -0
  22. data/lib/generators/singtel_sdp_generator.rb +10 -0
  23. data/lib/generators/singtel_sdp_views_generator.rb +10 -0
  24. data/lib/resources/xsds/SingTelSDPRequest.xsd +41 -0
  25. data/lib/resources/xsds/SingTelSDPResponse.xsd +27 -0
  26. data/lib/singtel_sdp.rb +8 -0
  27. data/lib/singtel_sdp/engine.rb +51 -0
  28. data/lib/singtel_sdp/rails/routes.rb +11 -0
  29. data/lib/singtel_sdp/singtel_helper.rb +37 -0
  30. data/lib/singtel_sdp/version.rb +3 -0
  31. data/lib/tasks/singtel_sdp_tasks.rake +4 -0
  32. metadata +204 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 43a8326ed8b265c7ead7f7ea5c386a800a27d747
4
+ data.tar.gz: 7595fcfdcc6a294e7323ed5ea300bfc17d66d52d
5
+ SHA512:
6
+ metadata.gz: d3a6c5701955cdc968146710befd6774948c815b7e057c4edeb4147cb43762ceb14a4e81a970dac23f5a1d23da8d9045f091df68f3bcdc0cb29cc65b90559a1c
7
+ data.tar.gz: 8ed91a7879fdaf249983c2d17ce8cce74a70616477fb9297b1eaae5ca44f92b54d3e46a0426b9743014e7b646e4cbc75de9a30147e43b82f9eb1d5ce9da9494d
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012-2014 Dropmysite Pte Ltd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,134 @@
1
+ # SingtelSdp
2
+
3
+ The core of this gem its on `SingtelSdp::BaseAdapter` and `SingtelSdp::BaseAdapterController`.
4
+
5
+ Implementing these 2 classes will let you decide what to do with each request received from the sdp.
6
+
7
+ SingtelSdp let you forget about the xml connections, result codes and messages. It gives you the chance to focus on the implementation of the actions for each request.
8
+
9
+ This gem solves most of the hard problems with the integration with singtel.
10
+
11
+ ## Installing
12
+
13
+ ## Get the gem
14
+
15
+ Add this to your `Gemfile`.
16
+
17
+ ```
18
+ gem 'singtel_sdp', '~>1.0.0', git: 'git://github.com/dropmyemail/singtel_sdp.git'
19
+ ```
20
+
21
+ ## Create the adapter
22
+
23
+ Use the provided generator to create the model, controller and initializer file for SingtelSdp.
24
+
25
+ ```
26
+ rails g singtel_sdp
27
+ ```
28
+
29
+ ### Customize the models
30
+
31
+ `SingtelSdp::BaseAdapter` is an abstract class, You need to implement the abstract methods.
32
+
33
+ ``` ruby
34
+ # app/models/singtel_Adapter.rb
35
+ #
36
+ class SingtelAdapter < SingtelSdp::BaseAdapter
37
+ def roles
38
+ # here you should return a list of the possible roles. eg ['ADMIN','DEFAULT']
39
+ end
40
+
41
+ def find_singtel_customer(isvcustno)
42
+ # Find and return a singtel customer here, can be an instances of any class that represents an active customer.
43
+ end
44
+
45
+ def find_singtel_product(isvsubsid)
46
+ # Find and return a singtel product subscription here, can be an instances of any class that represents an active subscription to a product in your domain.
47
+ end
48
+
49
+ def find_singtel_user(isvuserid)
50
+ # Find and return your singtel user here, can be an instances of any class that represents your active user.
51
+ end
52
+
53
+ def on_create_customer
54
+ #create your singtel customer here. in arguments variable you ll find a hash with the params received in the request. eg: arguments[:ISVCUSTNO], return the ivcustno as a string if everything went fine, if not nil.
55
+ end
56
+
57
+ def on_update_customer
58
+ #update your singtel customer here. in arguments variable you ll find a hash with the params received in the request. eg: arguments[:ISVCUSTNO], return the ivcustno as a string if everything went fine, if not nil.
59
+ end
60
+
61
+ def on_delete_customer
62
+ #delete your singtel customer here. in arguments variable you ll find a hash with the params received in the request. eg: arguments[:ISVCUSTNO], return the ivcustno as a string if everything went fine, if not nil.
63
+ end
64
+
65
+ def on_create_product
66
+ # Create your singtel product here. In arguments variable you ll find a hash with the params received in the request. eg arguments[:ISVSUBSID], return the isvsubsid as a string if everything went fine, if not nil.
67
+ end
68
+
69
+ def on_update_product
70
+ # Update your singtel product here. In arguments variable you ll find a hash with the params received in the request. eg: arguments[:NEWISVSUBSID], return the newisvsubsid as a string if everything went fine, if not nil.
71
+ end
72
+
73
+ def on_delete_product
74
+ # Update your singtel product here. In arguments variable you ll find a hash with the params received in the request. eg: arguments[:NEWISVSUBSID], return the newisvsubsid as a string if everything went fine, if not nil.
75
+ end
76
+
77
+ def on_create_user
78
+ end
79
+
80
+ def on_update_user
81
+ end
82
+
83
+ def on_delete_user
84
+ end
85
+ end
86
+ ```
87
+
88
+ ### Customize the controller
89
+
90
+ The `SintelSdp::BaseAdapterController` should be overriden. You have to override `SingtelSdp::SingtelBaseAdapterController#sign\_in\_singtel\_user #sign\_in\_singtel\_user`.
91
+
92
+ Optionally you can override `SingtelSdp::SingtelBaseAdapterController#on\_singtel\_login\_success #on\_singtel\_login\_success` and `SingtelSdp::SingtelBaseAdapterController#on\_singtel\_login\_failure #on\_singtel\_login\_failure`
93
+
94
+ ``` ruby
95
+ # app/controller/singtel_controller.rb
96
+ class SingtelController < SingtelSdp::BaseAdapterController
97
+ def sign_in_singtel_user(isvuserid)
98
+ # this is an implementation :P
99
+ end
100
+ end
101
+ ```
102
+
103
+ ### Mounting the routes
104
+
105
+ We provide a shortcut so you can add the `SingtelSdp::BaseAdapterController BaseAdapterController` to your `routes.rb`.
106
+
107
+ Here's a snippet showing two different ways of mounting the routes:
108
+
109
+ ``` ruby
110
+ # your routes.rb
111
+ YourApp::Application.routes.draw do
112
+
113
+ # Will mount the default SingtelSdp:BaseAdapterController in the
114
+ # /singtel path.
115
+ add_singtel_sdp_routes
116
+ end
117
+ ```
118
+
119
+ ### Customize the invalid session template
120
+
121
+ SingtelSdp will redirect to invalid session template if an sso login fails:
122
+
123
+ * problems with the otp.
124
+ * problems with the conextion.
125
+
126
+ You can copy the the built in template into your app's directory structure and customize them:
127
+
128
+ ```
129
+ $ rails g singtel_sdp_views
130
+ ```
131
+
132
+ # LICENSE
133
+
134
+ MIT-LICENSE. Check LICENSE for more details
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'SingtelSdp'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
File without changes
@@ -0,0 +1,64 @@
1
+ class SingtelSdp::BaseAdapterController < ApplicationController
2
+ skip_before_filter :verify_authenticity_token
3
+ before_filter :parse_request, only: :adapter
4
+ before_filter :validate_request, only: :adapter
5
+ before_filter :validate_header, only: :adapter
6
+
7
+ #singtel/adapter
8
+ def adapter
9
+ @singtel_request.execute
10
+ @requestno = @singtel_request.requestno
11
+ @return_value = @singtel_request.return_value
12
+ @returncode = @singtel_request.returncode
13
+ logger.info @returncode
14
+ render(if @returncode == 0
15
+ "#{@singtel_request.action_method_name}_response"
16
+ else
17
+ :error_response
18
+ end)
19
+ end
20
+
21
+ #singtel/sso
22
+ def sso
23
+ isvuserid = SingtelAdapter.verify_otp(params['otp'])
24
+ isvuserid = SingtelAdapter.verify_otp(params['otp']) if isvuserid.nil?
25
+ if isvuserid && sign_in_singtel_user(isvuserid)
26
+ self.on_singtel_login_success
27
+ else
28
+ self.on_singtel_login_failure
29
+ end
30
+ end
31
+
32
+ def on_singtel_login_success
33
+ redirect_to root_path
34
+ end
35
+
36
+ def on_singtel_login_failure
37
+ redirect_to invalid_session_path
38
+ end
39
+
40
+ # Singtel_sdp engine call this method when an user is aproved by singtel.
41
+ # Here you need to loggin the User with the isvuserid received as a param to your site.
42
+ def sign_in_singtel_user(isvuserid)
43
+ raise NotImplementedError.new("You must implement sign in.")
44
+ end
45
+
46
+
47
+ def parse_request
48
+ @singtel_request = SingtelAdapter.new(request.raw_post)
49
+ end
50
+
51
+ def validate_request
52
+ unless @singtel_request.valid_sdp_call?
53
+ @returncode = @singtel_request.returncode
54
+ render :error_response
55
+ end
56
+ end
57
+
58
+ def validate_header
59
+ unless @singtel_request.valid_header?
60
+ @returncode = @singtel_request.returncode
61
+ render :error_response
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,400 @@
1
+ require 'builder'
2
+
3
+ class SingtelSdp::BaseAdapter
4
+ def initialize(sdp_xml_call)
5
+ @sdp_xml_call = sdp_xml_call
6
+ @code = SingtelSdp::ReturnCode.new
7
+ @resource
8
+ end
9
+
10
+
11
+ # In order to validate the role sent by singtel the possible roles should be
12
+ # defined.
13
+ #
14
+ # @return [List] of all the values that the role can have. eg: ['COOL USER','DEFAULT USER']
15
+ def roles
16
+ raise NotImplementedError.new("You must implement roles.")
17
+ end
18
+
19
+ # In order to validate the product sent by singtel the possible products should be
20
+ # defined.
21
+ #
22
+ # @return [List] of all the values that the product can take. eg: ['PROD1','PROD2']
23
+ def products
24
+ raise NotImplementedError.new("You must implement products.")
25
+ end
26
+
27
+ # In order to validate the SELECTFROM value sent by singtel the possible values should be
28
+ # defined.
29
+ #
30
+ # @return [List] of all the values that the SELECTFROM field can take.
31
+ # eg: [ 'LICENSE_SUMMARY' ]
32
+ def selectfrom_values
33
+ raise NotImplementedError.new("You must implement selectfrom_values.")
34
+ end
35
+
36
+ # As each implementation manage subscriptions in a different way the engine needs to know
37
+ # how to find a singtel subscription in your domain.
38
+ #
39
+ # @return [Class, nil] with the product instance in your domain.
40
+ def find_singtel_product(isvsubsid)
41
+ raise NotImplementedError.new('You must implement this method')
42
+ end
43
+
44
+ # As each implementation manage users in a different way the engine needs to know
45
+ # how to find a singtel user in your domain.
46
+ #
47
+ # @return [Class, nil] with the user instance in your domain.
48
+ def find_singtel_user(isvuserid)
49
+ raise NotImplementedError.new('You must implement this method')
50
+ end
51
+
52
+ # As each implementation manage customers in a different way the engin needs to know
53
+ # how to find a singtel customers in your domain.
54
+ #
55
+ # @return [Class, nil] with the customer instance in your domain.
56
+ def find_singtel_customer(isvcustno)
57
+ raise NotImplementedError.new('You must implement this method')
58
+ end
59
+
60
+
61
+ # Singtel_sdp engine needs a way to know if the user that singtel wants to work with
62
+ # exists or no. In this way the engine will be able to validate the input received in
63
+ # the domain of the adapter.
64
+ #
65
+ # @return [Class, nil] with the user instance in your domain.
66
+ def current_singtel_user
67
+ find_singtel_user(arguments[:ISVUSERID])
68
+ end
69
+
70
+ # For manageing update_product requests the engine needs to check if that subscription exists.
71
+ #
72
+ # @return [Class, nil] with the current_singtel_product of the request.
73
+ def current_singtel_product
74
+ find_singtel_product(arguments[:ISVSUBSID])
75
+ end
76
+
77
+ # For almost all request the isvcustno should be check in your domain thats why this methods
78
+ # returns the current customer
79
+ #
80
+ # @return [Class, nil] with the customer that comes in each request.
81
+ def current_singtel_customer
82
+ find_singtel_customer(arguments[:ISVCUSTNO])
83
+ end
84
+
85
+ [ :on_create_customer, :on_update_customer, :on_delete_customer, :on_select_customer,
86
+ :on_create_product, :on_update_product, :on_delete_product,
87
+ :on_create_user, :on_update_user, :on_delete_user ].each do |name|
88
+ # When singtel send an action for updating deleting or creating an entity you should
89
+ # represent that action in your domain. that means for example updating deleting or creating
90
+ # one of your users.
91
+ #
92
+ # @return [String, nil] the external id of the object that was updated,deleted or created.
93
+ # nil on failure
94
+ define_method name do
95
+ raise NotImplementedError.new("You must implement #{name}.")
96
+ end
97
+ end
98
+
99
+ def invalid_settings
100
+ @invalid_settings ||= [:userid, :password, :application,
101
+ :env, :adapterversion].reject do |key|
102
+ header_info[key] == SingtelSdp.send("isv#{key}")
103
+ end
104
+ end
105
+
106
+ # @return [Boolean] with true value is the xml is correctly formed
107
+ # and its an sdp call
108
+ def valid_sdp_call?
109
+ valid = !@sdp_xml_call.blank? && self.class.valid_request?(@sdp_xml_call)
110
+ unless valid
111
+ @code.origin = :source
112
+ @code.entity = :other
113
+ @code.custom = :invalid_xml
114
+ end
115
+ valid
116
+ end
117
+
118
+ def self.otp_xml_request_body(otp)
119
+ xml = Builder::XmlMarkup.new(indent: 2)
120
+ xml.instruct!
121
+ xml.SingTelSDPRequest xmlns: 'SingTelSDPRequest.xsd' do
122
+ xml.HeaderInfo '', userid: SingtelSdp.isvuserid, password: SingtelSdp.isvpassword,
123
+ application: SingtelSdp.isvapplication, env: SingtelSdp.isvenv,
124
+ adapterversion: SingtelSdp.isvadapterversion,
125
+ createdatetime:Time.now.strftime('%FT%T%z'),
126
+ requestno: Time.now.strftime('%Y%m%d%H%M%S%L')
127
+ xml.RequestDetail do
128
+ xml.Entity name: 'OTP', action:'SSO' do
129
+ xml.Item '', fieldname: 'OTP', datatype: 'string', value: otp
130
+ end
131
+ end
132
+ end
133
+ end
134
+
135
+ def self.verify_otp(otp)
136
+ url = SingtelSdp.sdp_url
137
+ xml_response = SingtelSdp::SingtelHelper.raw_post_to_sdp(otp_xml_request_body(otp), url)
138
+ response = parse_xml_response(xml_response) if xml_response
139
+ return response[:arguments][:ISVUSERID] if response
140
+ nil
141
+ end
142
+
143
+
144
+ # Used for validating a sdp request header.
145
+ # Checks the attibutes from the header and sets to source of the error
146
+ # that will yield the proper error code.
147
+ #
148
+ # @return [Boolean] true is the header is correct
149
+ def valid_header?
150
+ unless invalid_settings.empty?
151
+ @code.origin = :source
152
+ @code.entity = :customer
153
+ end
154
+
155
+ case
156
+ when !(invalid_settings & [:userid, :password]).empty?
157
+ when invalid_settings.include?(:application)
158
+ @code.custom = :invalid_application
159
+ when invalid_settings.include?(:env)
160
+ @code.custom = :invalid_environment
161
+ when invalid_settings.include?(:adapterversion)
162
+ @code.custom = :invalid_adapterversion
163
+ end
164
+
165
+ !@code.has_errors?
166
+ end
167
+
168
+ # Contains an the xml request parsed by Nokogiri
169
+ # @return [Hash] with the request parsed
170
+ def parsed
171
+ @parsed ||= self.class.parse_xml_request(@sdp_xml_call)
172
+ end
173
+
174
+ # @returns [Hash] with the accessor to the header node from the parsed request
175
+ def header_info
176
+ parsed[:header_info]
177
+ end
178
+
179
+ # returns all the params
180
+ def arguments
181
+ parsed[:request_details][:arguments]
182
+ end
183
+
184
+ def entity
185
+ parsed[:request_details][:name].downcase.to_sym
186
+ end
187
+
188
+ def action
189
+ parsed[:request_details][:action].to_sym
190
+ end
191
+
192
+ def action_method_name
193
+ "#{action}_#{entity}"
194
+ end
195
+
196
+ def execute
197
+ @code.action = action
198
+ @code.entity = action == :select ? :customer_for_select : entity
199
+ @return_value = send(action_method_name)
200
+ @code.origin = :target unless @return_value or has_errors?
201
+ end
202
+
203
+ def return_value
204
+ @return_value
205
+ end
206
+
207
+ def returncode
208
+ @code.generate
209
+ end
210
+
211
+ # This is for setting the request number in an specific response. That means that a
212
+ # response for a request will have the same requestno.
213
+ #
214
+ # @return [String] with the requestno that came in the request.
215
+ def requestno
216
+ header_info[:requestno]
217
+ end
218
+
219
+ # mainly use for testing purpose
220
+ def has_errors?
221
+ @code.has_errors?
222
+ end
223
+
224
+ def create_customer
225
+ validate_customer_arguments
226
+ return if @code.has_errors?
227
+ self.on_create_customer
228
+ end
229
+
230
+ def update_customer
231
+ validate_customer_arguments
232
+ return if @code.has_errors?
233
+ self.on_update_customer
234
+ end
235
+
236
+ def delete_customer
237
+ validate_customer_arguments
238
+ return if @code.has_errors?
239
+ self.on_delete_customer
240
+ end
241
+
242
+ def select_customer
243
+ validate_customer_arguments
244
+ return if @code.has_errors?
245
+ self.on_select_customer
246
+ end
247
+
248
+ def create_product
249
+ validate_product_arguments
250
+ validate_customer_arguments
251
+ return if @code.has_errors?
252
+ self.on_create_product
253
+ end
254
+
255
+ # In case of an update in a subscription we check the amount of accounts that
256
+ # the previous account represented and replace that ammount in the max_account
257
+ # value. This value contains the max ammount of accounts that an organization
258
+ # backup
259
+ def update_product
260
+ validate_product_arguments
261
+ validate_customer_arguments
262
+ return if @code.has_errors?
263
+ self.on_update_product
264
+ end
265
+
266
+ def delete_product
267
+ validate_customer_arguments
268
+ validate_product_arguments
269
+ return if @code.has_errors?
270
+ deleted_extenal_id = on_delete_product
271
+ @code.origin = :target unless deleted_extenal_id
272
+ deleted_extenal_id
273
+ end
274
+
275
+ def create_user
276
+ validate_customer_arguments
277
+ validate_user_arguments
278
+ return if @code.has_errors?
279
+ self.on_create_user
280
+ end
281
+
282
+ def update_user
283
+ validate_user_arguments
284
+ return if @code.has_errors?
285
+ self.on_update_user
286
+ end
287
+
288
+ def delete_user
289
+ validate_user_arguments
290
+ validate_customer_arguments
291
+ return if @code.has_errors?
292
+ self.on_delete_user
293
+ end
294
+
295
+ def validate_customer_arguments
296
+ if entity == :customer && action == :select
297
+ @code.origin = :select_method
298
+ if !current_singtel_customer
299
+ @code.custom = :customer_not_found_for_select
300
+ elsif not selectfrom_values.include?(arguments[:SELECTFROM])
301
+ @code.custom = :invalid_selectfrom_value
302
+ end
303
+ else
304
+ if entity == :customer && action == :create
305
+ @code.origin = :source if current_singtel_customer
306
+ elsif current_singtel_customer.nil?
307
+ @code.origin = :source
308
+ @code.custom = :customer_not_found if [:user, :product].include?(entity)
309
+ end
310
+ end
311
+ current_singtel_customer
312
+ end
313
+
314
+
315
+ class << self
316
+ def valid_xml?(xml, xsd_path)
317
+ doc = Nokogiri::XML(xml)
318
+ xsd = Nokogiri::XML::Schema(File.read(xsd_path))
319
+ xsd.valid?(doc)
320
+ end
321
+
322
+ def valid_request?(xml)
323
+ valid_xml?(xml, SingtelSdp::REQUEST_XSD)
324
+ end
325
+
326
+ def valid_response?(xml)
327
+ valid_xml?(xml, SingtelSdp::RESPONSE_XSD)
328
+ end
329
+
330
+ def parser
331
+ if @_parser.nil?
332
+ @_parser = Nori.new(convert_tags_to: lambda { |tag| tag.gsub('@', '').to_sym })
333
+ end
334
+ @_parser
335
+ end
336
+
337
+ def parse_xml_request(xml)
338
+ result = {}
339
+ main_node = parser.parse(xml)[:SingTelSDPRequest]
340
+ result[:header_info] = get_header(main_node[:HeaderInfo])
341
+ request_details = main_node[:RequestDetail][:Entity]
342
+ request_details[:arguments] = get_arguments(request_details)
343
+ result[:request_details] = request_details
344
+ result
345
+ end
346
+
347
+ def parse_xml_response(xml)
348
+ result = {}
349
+ main_node = parser.parse(xml)[:SingTelSDPResponse]
350
+ response = main_node[:Result]
351
+ return unless response[:returncode].to_i == 0
352
+ result[:arguments] = get_arguments(response)
353
+ result[:response] = response
354
+ result
355
+ end
356
+
357
+ def get_header(header)
358
+ header[:createdatetime] = DateTime.parse(header[:createdatetime])
359
+ header
360
+ end
361
+
362
+ def get_arguments(node)
363
+ items = node.delete(:Item)
364
+ items = [items] unless items.is_a? Array
365
+ Hash[items.collect{ |i| [i[:fieldname].to_sym, i[:value]] }]
366
+ end
367
+ end
368
+
369
+
370
+ private
371
+
372
+ def validate_user_arguments
373
+ user = current_singtel_user
374
+ if !roles.include?(arguments[:ISVUSERROLE]) && action != :delete
375
+ @code.origin = :source
376
+ @code.custom = :invalid_user_role
377
+ elsif entity == :user && action == :create
378
+ @code.origin = :source if user
379
+ elsif user.nil?
380
+ @code.origin = :source
381
+ end
382
+
383
+ user
384
+ end
385
+
386
+ def validate_product_arguments
387
+ if !products.include?(arguments[:NEWISVPRODID]) && action == :update or
388
+ !products.include?(arguments[:ISVPRODID]) && action == :create
389
+ @code.origin = :source
390
+ @code.custom = :invalid_product_name
391
+ elsif arguments[:NEWISVSUBSID] && find_singtel_product(arguments[:NEWISVSUBSID])
392
+ @code.custom = :duplicated_subscription
393
+ @code.origin = :source
394
+ elsif current_singtel_product.nil? && action != :create
395
+ @code.origin = :source
396
+ end
397
+ current_singtel_product
398
+ end
399
+
400
+ end
@@ -0,0 +1,113 @@
1
+ class SingtelSdp::ReturnCode
2
+ ORIGINS = { no_error: 0, target: 1, source: 2, customer_data: 3, select_method: 6 }
3
+ ACTIONS = { general: 0, create: 2, update: 4, delete: 6, select: 0 }
4
+ ENTITIES = { general: 0, other: 1, customer: 2, product: 4, user: 6, customer_for_select: 0 }
5
+ CUSTOM_DIGIT = { general: 0, invalid_application: 1,
6
+ invalid_product_name: 1, invalid_user_role: 1,
7
+ invalid_environment: 3, invalid_adapterversion: 4,
8
+ duplicated_subscription: 4, invalid_xml: 5,
9
+ customer_not_found: 5,
10
+ customer_not_found_for_select: 1, invalid_selectfrom_value: 2 }
11
+
12
+ RETURN_MESSAGES = {
13
+ 0 => 'Success',
14
+ -1 => 'In Progress',
15
+ 1000 => 'General Error',
16
+ 1220 => 'Failed to Create Customer',
17
+ 1240 => 'Failed to Create Product',
18
+ 1260 => 'Failed to Create User',
19
+ 1420 => 'Failed to Update Customer',
20
+ 1440 => 'Failed to Update Product',
21
+ 1460 => 'Failed to Update User',
22
+ 1620 => 'Failed to Delete Customer',
23
+ 1640 => 'Failed to Delete Product',
24
+ 1660 => 'Failed to Delete User',
25
+ 2000 => 'Invalid OTP',
26
+ 2010 => 'Invalid Source Server',
27
+ 2015 => 'Invalid Request XML',
28
+ 2016 => 'Invalid Response XML',
29
+ 2020 => 'Invalid UserID and Password',
30
+ 2021 => 'Invalid application name',
31
+ 2023 => 'Invalid environment',
32
+ 2024 => 'Invalid adapter version',
33
+ 2025 => 'Invalid CreateDatetime',
34
+ 2026 => 'Duplicated requestno',
35
+ 2040 => 'Invalid Entity type',
36
+ 2041 => 'Invalid Action type',
37
+ 2220 => 'Duplicated Customer',
38
+ 2240 => 'Duplicated Subscription',
39
+ 2241 => 'Invalid Product Name',
40
+ 2242 => 'Invalid Trial Indicator',
41
+ 2243 => 'Invalid Quantity',
42
+ 2245 => 'Customer not found',
43
+ 2260 => 'Duplicated User',
44
+ 2261 => 'Invalid User Role',
45
+ 2265 => 'Customer not found',
46
+ 2266 => 'Subscription not found',
47
+ 2420 => 'Customer Not found',
48
+ 2440 => 'Subscription Not found',
49
+ 2441 => 'Invalid Product Name',
50
+ 2442 => 'Invalid Trial Indicator',
51
+ 2443 => 'Invalid Quantity',
52
+ 2444 => 'Duplicated Subscription',
53
+ 2460 => 'User Not Found',
54
+ 2461 => 'Invalid User Role',
55
+ 2620 => 'Customer not found',
56
+ 2640 => 'Subscription not found',
57
+ 2645 => 'Customer not found',
58
+ 2660 => 'User not found',
59
+ 2665 => 'Customer not found',
60
+ 2666 => 'Subscription not found',
61
+ 3260 => 'Email cannot be null',
62
+ 3261 => 'Invalid Email account',
63
+ 3262 => 'Existing Email account detected',
64
+ 3263 => 'Exceeded allowed number of total users license',
65
+ 3264 => 'Exceeded allowed number of admin users license',
66
+ 3460 => 'Invalid Email account',
67
+ 3462 => 'Existing Email account',
68
+ 6001 => 'Customer not found',
69
+ 6002 => 'Invalid SELECTFROM value',
70
+ }
71
+
72
+ def initialize
73
+ # These are the four digits that will compose
74
+ # the final returncode
75
+ self.origin = :no_error
76
+ self.action = :general
77
+ self.entity = :general
78
+ self.custom = :general
79
+ end
80
+
81
+ def origin=(key)
82
+ @origin = ORIGINS[key]
83
+ end
84
+
85
+ def action=(key)
86
+ @action = ACTIONS[key]
87
+ end
88
+
89
+ def entity=(key)
90
+ @entity = ENTITIES[key]
91
+ end
92
+
93
+ def custom=(key)
94
+ @custom = CUSTOM_DIGIT[key]
95
+ end
96
+
97
+ def generate
98
+ return 0 unless has_errors?
99
+ "#{@origin}#{@action}#{@entity}#{@custom}".to_i
100
+ end
101
+
102
+ def message
103
+ RETURN_MESSAGES[generate]
104
+ end
105
+
106
+ def has_errors?
107
+ if @origin == ORIGINS[:select_method]
108
+ @custom != 0
109
+ else
110
+ @origin != 0
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,9 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo do
6
+ xml.Item '', fieldname: 'ISVCUSTNO', datatype: 'string',
7
+ value: @return_value
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo do
6
+ xml.Item '', fieldname: 'ISVSUBSID', datatype: 'string',
7
+ value: @return_value
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo do
6
+ xml.Item '', fieldname: 'ISVUSERID', datatype: 'string',
7
+ value: @return_value
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo
6
+ end
@@ -0,0 +1,6 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo
6
+ end
@@ -0,0 +1,6 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo
6
+ end
@@ -0,0 +1,7 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo
6
+ end
7
+
@@ -0,0 +1,11 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo do
6
+ xml.Data fieldid: 'USAGELICENSE_LIST' do
7
+ xml.Licenses total: @return_value[:total], assigned: @return_value[:assigned],
8
+ spare: @return_value[:spare]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo
6
+ end
@@ -0,0 +1,9 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo do
6
+ xml.Item '', fieldname: 'ISVSUBSID', datatype: 'string',
7
+ value: @return_value
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ xml.instruct!
2
+ xml.SingTelSDPResponse xmlns: 'SingTelSDPResponse.xsd' do
3
+ xml.Result returncode: @returncode,
4
+ returnmessage: SingtelSdp::ReturnCode::RETURN_MESSAGES[@returncode],
5
+ requestno: @requestno, moreinfo: @moreinfo
6
+ end
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,10 @@
1
+ require 'rails/generators'
2
+
3
+ class SingtelSdpGenerator < Rails::Generators::Base
4
+ self.source_root([File.expand_path("../../../app/views", __FILE__)])
5
+
6
+ desc 'creates the controller and initializer file for SingtelSdp.'
7
+ def create_all
8
+ directory 'singtel_sdp', 'app/views'
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'rails/generators'
2
+
3
+ class SingtelSdpGenerator < Rails::Generators::Base
4
+ self.source_root([File.expand_path("../../../app/views", __FILE__)])
5
+
6
+ desc 'creates the controller and initializer file for SingtelSdp.'
7
+ def create_singtel_sdp_views
8
+ directory 'singtel_sdp', 'app/views'
9
+ end
10
+ end
@@ -0,0 +1,41 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <xs:schema id="SingTelSDPRequest" targetNamespace="SingTelSDPRequest.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
3
+ <xs:element name="SingTelSDPRequest">
4
+ <xs:complexType>
5
+ <xs:sequence>
6
+ <xs:element name="HeaderInfo" minOccurs="1" maxOccurs="1">
7
+ <xs:complexType>
8
+ <xs:attribute name="userid" type="xs:string" use="required" />
9
+ <xs:attribute name="password" type="xs:string" use="required" />
10
+ <xs:attribute name="application" type="xs:string" use="required" />
11
+ <xs:attribute name="env" type="xs:string" use="required" />
12
+ <xs:attribute name="adapterversion" type="xs:string" use="required" />
13
+ <xs:attribute name="createdatetime" type="xs:string" use="required" />
14
+ <xs:attribute name="requestno" type="xs:string" use="required" />
15
+ </xs:complexType>
16
+ </xs:element>
17
+ <xs:element name="RequestDetail" minOccurs="1" maxOccurs="1">
18
+ <xs:complexType>
19
+ <xs:sequence>
20
+ <xs:element name="Entity" minOccurs="1" maxOccurs="unbounded">
21
+ <xs:complexType>
22
+ <xs:sequence>
23
+ <xs:element name="Item" minOccurs="1" maxOccurs="unbounded">
24
+ <xs:complexType>
25
+ <xs:attribute name="fieldname" type="xs:string" use="required" />
26
+ <xs:attribute name="datatype" type="xs:string" use="required" />
27
+ <xs:attribute name="value" type="xs:string" use="required" />
28
+ </xs:complexType>
29
+ </xs:element>
30
+ </xs:sequence>
31
+ <xs:attribute name="name" type="xs:string" use="required" />
32
+ <xs:attribute name="action" type="xs:string" use="required" />
33
+ </xs:complexType>
34
+ </xs:element>
35
+ </xs:sequence>
36
+ </xs:complexType>
37
+ </xs:element>
38
+ </xs:sequence>
39
+ </xs:complexType>
40
+ </xs:element>
41
+ </xs:schema>
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <xs:schema id="SingTelSDPResponse" targetNamespace="SingTelSDPResponse.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"
3
+ elementFormDefault="qualified">
4
+ <xs:element name="SingTelSDPResponse">
5
+ <xs:complexType>
6
+ <xs:sequence>
7
+ <xs:element name="Result" minOccurs="1" maxOccurs="1">
8
+ <xs:complexType>
9
+ <xs:sequence>
10
+ <xs:element name="Item" minOccurs="0" maxOccurs="unbounded">
11
+ <xs:complexType>
12
+ <xs:attribute name="fieldname" type="xs:string" use="required" />
13
+ <xs:attribute name="datatype" type="xs:string" use="required" />
14
+ <xs:attribute name="value" type="xs:string" use="required" />
15
+ </xs:complexType>
16
+ </xs:element>
17
+ </xs:sequence>
18
+ <xs:attribute name="returncode" type="xs:string" use="required" />
19
+ <xs:attribute name="returnmessage" type="xs:string" use="required" />
20
+ <xs:attribute name="moreinfo" type="xs:string" use="required" />
21
+ <xs:attribute name="requestno" type="xs:string" use="required" />
22
+ </xs:complexType>
23
+ </xs:element>
24
+ </xs:sequence>
25
+ </xs:complexType>
26
+ </xs:element>
27
+ </xs:schema>
@@ -0,0 +1,8 @@
1
+ require "singtel_sdp/engine"
2
+ require "singtel_sdp/singtel_helper"
3
+ require "singtel_sdp/rails/routes"
4
+
5
+ module SingtelSdp
6
+ REQUEST_XSD = "#{File.dirname(__FILE__)}/../lib/resources/xsds/SingTelSDPRequest.xsd"
7
+ RESPONSE_XSD = "#{File.dirname(__FILE__)}/../lib/resources/xsds/SingTelSDPResponse.xsd"
8
+ end
@@ -0,0 +1,51 @@
1
+ require 'nori'
2
+ require 'nokogiri'
3
+ require 'hashie'
4
+
5
+ module SingtelSdp
6
+ # This is the url of sdp
7
+ # !@property mattr_accessor
8
+ # @returns [String] example: https://marketplace-uat.singtel.com/SSOBalance/
9
+ mattr_accessor :sdp_url
10
+
11
+ # This is the user id that singtel uses to identify in your application
12
+ # !@property mattr_accessor
13
+ # @returns [String] example: dropmyemail_singtel_user
14
+ mattr_accessor :isvuserid
15
+
16
+ # This is the password that singtel uses to identify in your application
17
+ # !@property mattr_accessor
18
+ # @returns [String] example: 123456
19
+ mattr_accessor :isvpassword
20
+
21
+ # This is the name you gave to singtel for your application.
22
+ # !@property mattr_accessor
23
+ # @returns [String] example: dropmyemail.com
24
+ mattr_accessor :isvapplication
25
+
26
+ # This is the current environment of the request.
27
+ # !@property mattr_accessor
28
+ # @returns [String] example: UAT
29
+ mattr_accessor :isvenv
30
+
31
+ # This is the version of your adapter.
32
+ # !@property mattr_accessor
33
+ # @returns [String] example: 0.1
34
+ mattr_accessor :isvadapterversion
35
+
36
+ def self.setup
37
+ config = Hashie::Mash.new
38
+ yield config
39
+ self.sdp_url = config.sdpurl
40
+ self.isvuserid = config.isvuserid
41
+ self.isvpassword = config.isvpassword
42
+ self.isvapplication = config.isvapplication
43
+ self.isvenv = config.isvenv
44
+ self.isvadapterversion = config.isvadapterversion
45
+ end
46
+
47
+ class Engine < ::Rails::Engine
48
+ initializer 'singtel_sdp starts nori configs' do |app|
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,11 @@
1
+ class ActionDispatch::Routing::Mapper
2
+ def add_singtel_sdp_routes(controller='singtel_sdp/singtel')
3
+ lambda do
4
+ scope '/singtel', module: :singtel do
5
+ match 'adapter', via: :all
6
+ match 'sso', via: :all
7
+ get 'invalid_session'
8
+ end
9
+ end.call
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ require 'net/http'
2
+ module SingtelSdp
3
+ class SingtelHelper
4
+ # This returns the absolute path of the engine whethere you are in the engine or in the host
5
+ # app.
6
+ def self.root
7
+ "#{File.dirname(__FILE__)}/../.."
8
+ end
9
+
10
+ # Validates a user provided OTP against Singtel SSO remote API.
11
+ # Response is an XML containing either an error or the valid user id.
12
+ # Returns nil if any network errors occur.
13
+ #
14
+ # @param xml [String] SSO request containing OTP
15
+ # @return [String,nil] XML response for the login attempt, nil on failure.
16
+ def self.raw_post_to_sdp(xml, url, ssl = true)
17
+ uri = URI.parse(url)
18
+ begin
19
+ http = Net::HTTP.new(uri.host, uri.port)
20
+ http.use_ssl = ssl
21
+ request = Net::HTTP::Post.new(uri.path)
22
+ request.body = xml
23
+ request['Content-Type'] = 'text/xml'
24
+ response = http.request(request)
25
+ response.body
26
+ rescue => e
27
+ return nil
28
+ end
29
+ end
30
+
31
+ # retrives the content of some xml request and response examples
32
+ def self.xml_for(filename)
33
+ File.read("#{root}/spec/fixtures/singtel/samples/#{filename}.xml")
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module SingtelSdp
2
+ VERSION = "1.2.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :singtel_sdp do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: singtel_sdp
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Alan Moran
8
+ - Tomas Rojas
9
+ - Bruno Nubis
10
+ - Wong Liang Zan
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2014-10-30 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rails
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '4.1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '4.1'
30
+ - !ruby/object:Gem::Dependency
31
+ name: nokogiri
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ - !ruby/object:Gem::Dependency
45
+ name: nori
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ - !ruby/object:Gem::Dependency
59
+ name: haml
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ - !ruby/object:Gem::Dependency
73
+ name: hashie
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ - !ruby/object:Gem::Dependency
87
+ name: sqlite3
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ type: :development
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ - !ruby/object:Gem::Dependency
101
+ name: rspec-rails
102
+ requirement: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ type: :development
108
+ prerelease: false
109
+ version_requirements: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ - !ruby/object:Gem::Dependency
115
+ name: factory_girl_rails
116
+ requirement: !ruby/object:Gem::Requirement
117
+ requirements:
118
+ - - '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ - !ruby/object:Gem::Dependency
129
+ name: capybara
130
+ requirement: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ type: :development
136
+ prerelease: false
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: |2
143
+ Rails 4 engine that provides Singtel's SDP integration points to your rails app.
144
+ Processes and translates requestes for the standard CRUD actions for Customers, Products, Users and OAuth SSO.
145
+ email:
146
+ - zan@dropmysite.com
147
+ executables: []
148
+ extensions: []
149
+ extra_rdoc_files: []
150
+ files:
151
+ - app/assets/stylesheets/application.css
152
+ - app/controllers/singtel_sdp/base_adapter_controller.rb
153
+ - app/models/singtel_sdp/base_adapter.rb
154
+ - app/models/singtel_sdp/return_code.rb
155
+ - app/views/singtel_sdp/base_adapter/create_customer_response.xml.builder
156
+ - app/views/singtel_sdp/base_adapter/create_product_response.xml.builder
157
+ - app/views/singtel_sdp/base_adapter/create_user_response.xml.builder
158
+ - app/views/singtel_sdp/base_adapter/delete_customer_response.xml.builder
159
+ - app/views/singtel_sdp/base_adapter/delete_product_response.xml.builder
160
+ - app/views/singtel_sdp/base_adapter/delete_user_response.xml.builder
161
+ - app/views/singtel_sdp/base_adapter/error_response.xml.builder
162
+ - app/views/singtel_sdp/base_adapter/invalid_session.html.haml
163
+ - app/views/singtel_sdp/base_adapter/select_customer_response.xml.builder
164
+ - app/views/singtel_sdp/base_adapter/update_customer_response.xml.builder
165
+ - app/views/singtel_sdp/base_adapter/update_product_response.xml.builder
166
+ - app/views/singtel_sdp/base_adapter/update_user_response.xml.builder
167
+ - config/routes.rb
168
+ - lib/generators/singtel_sdp_generator.rb
169
+ - lib/generators/singtel_sdp_views_generator.rb
170
+ - lib/resources/xsds/SingTelSDPRequest.xsd
171
+ - lib/resources/xsds/SingTelSDPResponse.xsd
172
+ - lib/singtel_sdp/engine.rb
173
+ - lib/singtel_sdp/rails/routes.rb
174
+ - lib/singtel_sdp/singtel_helper.rb
175
+ - lib/singtel_sdp/version.rb
176
+ - lib/singtel_sdp.rb
177
+ - lib/tasks/singtel_sdp_tasks.rake
178
+ - LICENSE
179
+ - Rakefile
180
+ - README.md
181
+ homepage: https://github.com/dropmyemail/singtel_sdp
182
+ licenses: []
183
+ metadata: {}
184
+ post_install_message:
185
+ rdoc_options: []
186
+ require_paths:
187
+ - lib
188
+ required_ruby_version: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - '>='
191
+ - !ruby/object:Gem::Version
192
+ version: '0'
193
+ required_rubygems_version: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - '>='
196
+ - !ruby/object:Gem::Version
197
+ version: '0'
198
+ requirements: []
199
+ rubyforge_project:
200
+ rubygems_version: 2.0.14
201
+ signing_key:
202
+ specification_version: 4
203
+ summary: Provides Singtel's SDP integration points to your rails app
204
+ test_files: []