singtel_sdp 1.2.0

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.
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: []