stormpath-sdk 0.4.0 → 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/.gitignore +6 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +27 -0
  5. data/CHANGES.md +21 -1
  6. data/Gemfile +1 -2
  7. data/README.md +457 -11
  8. data/Rakefile +15 -1
  9. data/lib/stormpath-sdk.rb +52 -33
  10. data/lib/stormpath-sdk/{resource/group_list.rb → api_key.rb} +5 -9
  11. data/lib/stormpath-sdk/auth/authentication_result.rb +3 -13
  12. data/lib/stormpath-sdk/auth/basic_authenticator.rb +5 -11
  13. data/lib/stormpath-sdk/auth/basic_login_attempt.rb +6 -8
  14. data/lib/stormpath-sdk/auth/username_password_request.rb +2 -5
  15. data/lib/stormpath-sdk/cache/cache.rb +54 -0
  16. data/lib/stormpath-sdk/cache/cache_entry.rb +33 -0
  17. data/lib/stormpath-sdk/cache/cache_manager.rb +22 -0
  18. data/lib/stormpath-sdk/cache/cache_stats.rb +35 -0
  19. data/lib/stormpath-sdk/cache/memory_store.rb +29 -0
  20. data/lib/stormpath-sdk/cache/redis_store.rb +32 -0
  21. data/lib/stormpath-sdk/client.rb +111 -0
  22. data/lib/stormpath-sdk/data_store.rb +241 -0
  23. data/lib/stormpath-sdk/{client/api_key.rb → error.rb} +16 -10
  24. data/lib/stormpath-sdk/{util → ext}/hash.rb +1 -2
  25. data/lib/stormpath-sdk/http/authc/sauthc1_signer.rb +8 -4
  26. data/lib/stormpath-sdk/http/http_client_request_executor.rb +8 -7
  27. data/lib/stormpath-sdk/http/request.rb +4 -8
  28. data/lib/stormpath-sdk/{util/request_utils.rb → http/utils.rb} +17 -38
  29. data/lib/stormpath-sdk/resource/account.rb +12 -108
  30. data/lib/stormpath-sdk/resource/application.rb +35 -171
  31. data/lib/stormpath-sdk/resource/associations.rb +97 -0
  32. data/lib/stormpath-sdk/resource/base.rb +256 -0
  33. data/lib/stormpath-sdk/resource/collection.rb +94 -0
  34. data/lib/stormpath-sdk/resource/directory.rb +11 -68
  35. data/lib/stormpath-sdk/resource/email_verification_token.rb +3 -9
  36. data/lib/stormpath-sdk/resource/error.rb +4 -38
  37. data/lib/stormpath-sdk/resource/expansion.rb +28 -0
  38. data/lib/stormpath-sdk/resource/group.rb +8 -66
  39. data/lib/stormpath-sdk/resource/group_membership.rb +4 -55
  40. data/lib/stormpath-sdk/resource/{application_list.rb → instance.rb} +7 -13
  41. data/lib/stormpath-sdk/resource/password_reset_token.rb +5 -23
  42. data/lib/stormpath-sdk/resource/status.rb +22 -28
  43. data/lib/stormpath-sdk/resource/tenant.rb +5 -52
  44. data/lib/stormpath-sdk/resource/utils.rb +43 -13
  45. data/lib/stormpath-sdk/util/assert.rb +5 -15
  46. data/lib/stormpath-sdk/version.rb +3 -3
  47. data/spec/api_key_spec.rb +19 -0
  48. data/spec/auth/basic_authenticator_spec.rb +25 -0
  49. data/spec/auth/sauthc1_signer_spec.rb +42 -0
  50. data/spec/cache/cache_entry_spec.rb +157 -0
  51. data/spec/cache/cache_spec.rb +89 -0
  52. data/spec/cache/cache_stats_spec.rb +106 -0
  53. data/spec/client_spec.rb +538 -0
  54. data/spec/data_store_spec.rb +130 -0
  55. data/spec/resource/account_spec.rb +74 -0
  56. data/spec/resource/application_spec.rb +148 -0
  57. data/spec/resource/base_spec.rb +114 -0
  58. data/spec/resource/collection_spec.rb +169 -0
  59. data/spec/resource/directory_spec.rb +30 -0
  60. data/spec/resource/expansion_spec.rb +100 -0
  61. data/spec/resource/group_spec.rb +49 -0
  62. data/spec/spec_helper.rb +135 -0
  63. data/spec/support/resource_factory.rb +48 -0
  64. data/spec/support/resource_matchers.rb +27 -0
  65. data/spec/support/test_cache_stores.rb +9 -0
  66. data/spec/support/test_request_executor.rb +11 -0
  67. data/stormpath-sdk.gemspec +14 -4
  68. data/support/api.rb +55 -0
  69. metadata +214 -44
  70. data/lib/stormpath-sdk/client/client.rb +0 -38
  71. data/lib/stormpath-sdk/client/client_application.rb +0 -38
  72. data/lib/stormpath-sdk/client/client_application_builder.rb +0 -351
  73. data/lib/stormpath-sdk/client/client_builder.rb +0 -305
  74. data/lib/stormpath-sdk/ds/data_store.rb +0 -210
  75. data/lib/stormpath-sdk/ds/resource_factory.rb +0 -37
  76. data/lib/stormpath-sdk/resource/account_list.rb +0 -32
  77. data/lib/stormpath-sdk/resource/collection_resource.rb +0 -91
  78. data/lib/stormpath-sdk/resource/directory_list.rb +0 -30
  79. data/lib/stormpath-sdk/resource/group_membership_list.rb +0 -32
  80. data/lib/stormpath-sdk/resource/instance_resource.rb +0 -28
  81. data/lib/stormpath-sdk/resource/resource.rb +0 -327
  82. data/lib/stormpath-sdk/resource/resource_error.rb +0 -47
  83. data/test/client/client.yml +0 -16
  84. data/test/client/client_application_builder_spec.rb +0 -114
  85. data/test/client/client_builder_spec.rb +0 -176
  86. data/test/client/read_spec.rb +0 -254
  87. data/test/client/write_spec.rb +0 -420
  88. data/test/resource/resource_spec.rb +0 -41
  89. data/test/resource/test_resource.rb +0 -28
@@ -0,0 +1,97 @@
1
+ module Stormpath
2
+ module Resource
3
+ module Associations
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+
8
+ def resource_prop_reader(*args)
9
+ args.each do |name|
10
+ resource_class = "Stormpath::Resource::#{name.to_s.camelize}".constantize
11
+ property_name = name.to_s.camelize :lower
12
+
13
+ define_method(name) do
14
+ get_resource_property property_name, resource_class
15
+ end
16
+ end
17
+ end
18
+
19
+ alias_method :has_one, :resource_prop_reader
20
+ alias_method :belongs_to, :resource_prop_reader
21
+
22
+ def has_many(name, options={}, &block)
23
+ item_class = options[:class] || "Stormpath::Resource::#{name.to_s.singularize.camelize}".constantize
24
+ property_name = name.to_s.camelize :lower
25
+ can = Array.wrap(options[:can]) || []
26
+
27
+ define_method(name) do
28
+ href = options[:href] || get_resource_href_property(property_name)
29
+ collection_href = if options[:delegate]
30
+ "#{tenant.applications.first.tenant.href}/#{name.to_s}"
31
+ end
32
+
33
+ Stormpath::Resource::Collection.new(href, item_class, client,
34
+ collection_href: collection_href).tap do |collection|
35
+
36
+ collection.class_eval do
37
+ if can.include? :create
38
+ def create(properties_or_resource)
39
+ resource = case properties_or_resource
40
+ when Stormpath::Resource::Base
41
+ properties_or_resource
42
+ else
43
+ item_class.new properties_or_resource, client
44
+ end
45
+ data_store.create href, resource, item_class
46
+ end
47
+ end
48
+
49
+ if can.include? :get
50
+ def get(id_or_href, expansion=nil)
51
+ item_href = if id_or_href.index '/'
52
+ id_or_href
53
+ else
54
+ "#{href}/#{id_or_href}"
55
+ end
56
+ data_store.get_resource item_href, item_class, (expansion ? expansion.to_query : nil)
57
+ end
58
+ end
59
+ end
60
+
61
+ collection.class_eval(&block) if block
62
+ end
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ included do
69
+
70
+ private
71
+
72
+ def get_resource_property(key, clazz)
73
+ value = get_property key
74
+
75
+ if value.is_a? Hash
76
+ href = get_href_from_hash value
77
+ end
78
+
79
+ unless href.nil?
80
+ data_store.instantiate clazz, value
81
+ end
82
+ end
83
+
84
+ def get_resource_href_property(key)
85
+ value = get_property key
86
+
87
+ if value.is_a? Hash
88
+ get_href_from_hash value
89
+ else
90
+ nil
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,256 @@
1
+ #
2
+ # Copyright 2012 Stormpath, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ class Stormpath::Resource::Base
17
+ include Stormpath::Resource::Utils
18
+ include Stormpath::Resource::Associations
19
+
20
+ HREF_PROP_NAME = "href"
21
+
22
+ attr_reader :client, :properties
23
+
24
+ class << self
25
+ def prop_reader(*args)
26
+ args.each do |name|
27
+ property_name = name.to_s.camelize :lower
28
+
29
+ define_method(name) do
30
+ get_property property_name
31
+ end
32
+ end
33
+ end
34
+
35
+ def prop_writer(*args)
36
+ args.each do |name|
37
+ property_name = name.to_s.camelize :lower
38
+
39
+ define_method("#{name.to_s}=") do |value|
40
+ set_property property_name, value
41
+ end
42
+ end
43
+ end
44
+
45
+ def prop_accessor(*args)
46
+ args.each do |name|
47
+ prop_reader name
48
+ prop_writer name
49
+ end
50
+ end
51
+
52
+ def prop_non_printable(*args)
53
+ @non_printable_properties ||= []
54
+ args.each do |name|
55
+ property_name = name.to_s.camelize :lower
56
+ @non_printable_properties << property_name
57
+ end
58
+ end
59
+
60
+ def non_printable_properties
61
+ @non_printable_properties ||= []
62
+ Array.new @non_printable_properties
63
+ end
64
+ end
65
+
66
+ def initialize properties_or_url, client=nil, query=nil
67
+ properties = case properties_or_url
68
+ when String
69
+ { HREF_PROP_NAME => properties_or_url }
70
+ when Hash
71
+ properties_or_url
72
+ else
73
+ {}
74
+ end
75
+
76
+ @client = client
77
+ @query = query
78
+ @read_lock = Mutex.new
79
+ @write_lock = Mutex.new
80
+ @properties = Hash.new
81
+ @dirty_properties = Hash.new
82
+ set_properties properties
83
+ end
84
+
85
+ def new?
86
+ prop = read_property HREF_PROP_NAME
87
+
88
+ if prop.nil?
89
+ true
90
+ else
91
+ prop.respond_to? 'empty' and prop.empty?
92
+ end
93
+ end
94
+
95
+ def href
96
+ get_property HREF_PROP_NAME
97
+ end
98
+
99
+ def get_property_names
100
+ @read_lock.lock
101
+
102
+ begin
103
+ @properties.keys
104
+ ensure
105
+ @read_lock.unlock
106
+ end
107
+ end
108
+
109
+ def set_properties properties
110
+ @write_lock.lock
111
+
112
+ begin
113
+ @properties.clear
114
+ @dirty_properties.clear
115
+ @dirty = false
116
+
117
+ unless properties.nil?
118
+ @properties = deep_sanitize properties
119
+
120
+ # Don't consider this resource materialized if it is only a reference. A reference is any object that
121
+ # has only one 'href' property.
122
+ href_only = (@properties.size == 1 and @properties.has_key? HREF_PROP_NAME)
123
+ @materialized = !href_only
124
+ else
125
+ @materialized = false
126
+ end
127
+
128
+ ensure
129
+ @write_lock.unlock
130
+ end
131
+ end
132
+
133
+ def get_property name
134
+ property_name = name.to_s.camelize :lower
135
+
136
+ if !HREF_PROP_NAME.eql? property_name
137
+ #not the href/id, must be a property that requires materialization:
138
+ unless new? or materialized?
139
+
140
+ # only materialize if the property hasn't been set previously (no need to execute a server
141
+ # request since we have the most recent value already):
142
+ present = false
143
+
144
+ @read_lock.lock
145
+ begin
146
+ present = @dirty_properties.has_key? property_name
147
+ ensure
148
+ @read_lock.unlock
149
+ end
150
+
151
+ unless present
152
+ # exhausted present properties - we require a server call:
153
+ materialize
154
+ end
155
+ end
156
+ end
157
+
158
+ read_property name
159
+ end
160
+
161
+ def set_property name, value
162
+ property_name = name.to_s.camelize :lower
163
+ @write_lock.lock
164
+
165
+ begin
166
+ @properties.store property_name, value
167
+ @dirty_properties.store property_name, value
168
+ @dirty = true
169
+ ensure
170
+ @write_lock.unlock
171
+ end
172
+ end
173
+
174
+ def == other
175
+ if other.is_a?(self.class)
176
+ href == other.href
177
+ else
178
+ super
179
+ end
180
+ end
181
+
182
+ protected
183
+
184
+ def data_store
185
+ client.data_store
186
+ end
187
+
188
+ def materialized?
189
+ @materialized
190
+ end
191
+
192
+ def materialize
193
+ clazz = self.class
194
+
195
+ @write_lock.lock
196
+
197
+ begin
198
+ resource = data_store.get_resource href, clazz, @query
199
+ @properties.replace resource.properties
200
+
201
+ #retain dirty properties:
202
+ @properties.merge! @dirty_properties
203
+
204
+ @materialized = true
205
+ ensure
206
+ @write_lock.unlock
207
+ end
208
+ end
209
+
210
+ def printable_property? property_name
211
+ !self.class.non_printable_properties.include? property_name
212
+ end
213
+
214
+ private
215
+
216
+ def get_href_from_hash(props)
217
+ if !props.nil? and props.is_a? Hash
218
+ props[HREF_PROP_NAME]
219
+ end
220
+ end
221
+
222
+ def read_property name
223
+ @read_lock.lock
224
+
225
+ begin
226
+ @properties[name]
227
+ ensure
228
+ @read_lock.unlock
229
+ end
230
+ end
231
+
232
+ def sanitize(properties)
233
+ {}.tap do |sanitized_properties|
234
+ properties.map do |key, value|
235
+ property_name = key.to_s.camelize :lower
236
+
237
+ sanitized_properties[property_name] =
238
+ if (value.kind_of? Hash) or
239
+ (value.kind_of? Stormpath::Resource::Base)
240
+ deep_sanitize value
241
+ else
242
+ value
243
+ end
244
+ end
245
+ end
246
+ end
247
+
248
+ def deep_sanitize(hash_or_resource)
249
+ case hash_or_resource
250
+ when Stormpath::Resource::Base
251
+ deep_sanitize hash_or_resource.properties
252
+ when Hash
253
+ sanitize hash_or_resource
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,94 @@
1
+ #
2
+ # Copyright 2012 Stormpath, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+ class Stormpath::Resource::Collection
17
+ include Enumerable
18
+
19
+ attr_reader :href, :client, :item_class, :collection_href, :criteria
20
+
21
+ def initialize(href, item_class, client, options={})
22
+ @client = client
23
+ @href = href
24
+ @item_class = item_class
25
+ @collection_href = options[:collection_href] || @href
26
+ @criteria ||= {}
27
+ end
28
+
29
+ def data_store
30
+ client.data_store
31
+ end
32
+
33
+ def search query
34
+ query_hash = if query.is_a? String
35
+ { q: query }
36
+ elsif query.is_a? Hash
37
+ query
38
+ end
39
+
40
+ criteria.merge! query_hash
41
+ self
42
+ end
43
+
44
+ def offset offset
45
+ criteria.merge! offset: offset
46
+ self
47
+ end
48
+
49
+ def limit limit
50
+ criteria.merge! limit: limit
51
+ self
52
+ end
53
+
54
+ def order statement
55
+ criteria.merge! order_by: statement
56
+ self
57
+ end
58
+
59
+ def each(&block)
60
+ page = CollectionPage.new collection_href, client, @criteria
61
+ page.item_type = item_class
62
+ items = page.items
63
+ items.each(&block)
64
+ end
65
+
66
+ private
67
+
68
+ class CollectionPage < Stormpath::Resource::Base
69
+ ITEMS = 'items'
70
+
71
+ prop_accessor :offset, :limit
72
+
73
+ attr_accessor :item_type
74
+
75
+ def items
76
+ to_resource_array get_property ITEMS
77
+ end
78
+
79
+ def to_resource properties
80
+ data_store.instantiate item_type, properties
81
+ end
82
+
83
+ def to_resource_array vals
84
+ Array.new.tap do |items|
85
+ if vals.is_a? Array
86
+ vals.each do |val|
87
+ resource = to_resource val
88
+ items << resource
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -13,79 +13,22 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- module Stormpath
16
+ class Stormpath::Resource::Directory < Stormpath::Resource::Instance
17
+ include Stormpath::Resource::Status
17
18
 
18
- module Resource
19
+ prop_accessor :name, :description
19
20
 
20
- class Directory < InstanceResource
21
+ belongs_to :tenant
21
22
 
22
- include Status
23
-
24
- NAME = "name"
25
- DESCRIPTION = "description"
26
- STATUS = "status"
27
- ACCOUNTS = "accounts"
28
- GROUPS = "groups"
29
- TENANT = "tenant"
30
-
31
- def get_name
32
- get_property NAME
33
- end
34
-
35
- def set_name name
36
- set_property NAME, name
37
- end
38
-
39
- def get_description
40
- get_property DESCRIPTION
41
- end
42
-
43
- def set_description description
44
- set_property DESCRIPTION, description
45
- end
46
-
47
- def get_status
48
- value = get_property STATUS
49
-
50
- if !value.nil?
51
- value = value.upcase
52
- end
53
-
54
- value
55
- end
56
-
57
- def set_status status
58
-
59
- if get_status_hash.has_key? status
60
- set_property STATUS, get_status_hash[status]
61
- end
62
-
63
- end
64
-
65
- def create_account account, *registration_workflow_enabled
66
- accounts = get_accounts
67
- href = accounts.get_href
68
- if !registration_workflow_enabled.nil? and !registration_workflow_enabled.empty?
69
- href += '?registrationWorkflowEnabled=' + registration_workflow_enabled[0].to_s
70
- end
71
-
72
- data_store.create href, account, Account
73
- end
74
-
75
- def get_accounts
76
- get_resource_property ACCOUNTS, AccountList
77
- end
78
-
79
- def get_groups
80
- get_resource_property GROUPS, GroupList
81
- end
82
-
83
- def get_tenant
84
- get_resource_property TENANT, Tenant
85
- end
23
+ has_many :accounts, can: :create
24
+ has_many :groups, can: :create
86
25
 
26
+ def create_account account, registration_workflow_enabled=nil
27
+ href = accounts.href
28
+ unless registration_workflow_enabled.nil?
29
+ href += "?registrationWorkflowEnabled=#{registration_workflow_enabled.to_s}"
87
30
  end
88
31
 
32
+ data_store.create href, account, Stormpath::Resource::Account
89
33
  end
90
34
  end
91
-