stormpath-sdk 0.4.0 → 1.0.0.beta

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