stormpath-sdk 1.0.0.beta.4 → 1.0.0.beta.5

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 (37) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGES.md +15 -0
  3. data/README.md +35 -3
  4. data/lib/stormpath-sdk.rb +5 -6
  5. data/lib/stormpath-sdk/auth/basic_authenticator.rb +2 -0
  6. data/lib/stormpath-sdk/auth/basic_login_attempt.rb +11 -0
  7. data/lib/stormpath-sdk/auth/username_password_request.rb +6 -12
  8. data/lib/stormpath-sdk/data_store.rb +118 -127
  9. data/lib/stormpath-sdk/http/http_client_request_executor.rb +10 -42
  10. data/lib/stormpath-sdk/resource/account.rb +13 -3
  11. data/lib/stormpath-sdk/resource/account_membership.rb +16 -0
  12. data/lib/stormpath-sdk/resource/account_status.rb +26 -0
  13. data/lib/stormpath-sdk/resource/account_store_mapping.rb +4 -2
  14. data/lib/stormpath-sdk/resource/application.rb +4 -2
  15. data/lib/stormpath-sdk/resource/associations.rb +7 -3
  16. data/lib/stormpath-sdk/resource/base.rb +21 -15
  17. data/lib/stormpath-sdk/resource/custom_data.rb +86 -0
  18. data/lib/stormpath-sdk/resource/custom_data_hash_methods.rb +33 -0
  19. data/lib/stormpath-sdk/resource/custom_data_storage.rb +39 -0
  20. data/lib/stormpath-sdk/resource/directory.rb +4 -4
  21. data/lib/stormpath-sdk/resource/expansion.rb +15 -0
  22. data/lib/stormpath-sdk/resource/group.rb +10 -0
  23. data/lib/stormpath-sdk/resource/status.rb +16 -5
  24. data/lib/stormpath-sdk/version.rb +2 -2
  25. data/spec/client_spec.rb +6 -1
  26. data/spec/data_store_spec.rb +7 -2
  27. data/spec/resource/account_spec.rb +73 -30
  28. data/spec/resource/account_store_mapping_spec.rb +20 -5
  29. data/spec/resource/application_spec.rb +135 -0
  30. data/spec/resource/custom_data_spec.rb +198 -0
  31. data/spec/resource/directory_spec.rb +192 -9
  32. data/spec/resource/group_membership_spec.rb +35 -0
  33. data/spec/resource/group_spec.rb +44 -26
  34. data/spec/resource/status_spec.rb +81 -0
  35. data/spec/resource/tenant_spec.rb +19 -0
  36. data/stormpath-sdk.gemspec +2 -2
  37. metadata +13 -3
@@ -14,25 +14,18 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  module Stormpath
17
-
18
17
  module Http
19
-
20
18
  class HttpClientRequestExecutor
21
-
22
19
  include Stormpath::Http::Authc
23
20
  include Stormpath::Util::Assert
24
21
 
25
- REDIRECTS_LIMIT = 10
26
-
27
22
  def initialize(api_key, options = {})
28
23
  @signer = Sauthc1Signer.new
29
24
  @api_key = api_key
30
25
  @http_client = HTTPClient.new options[:proxy]
31
- @redirects_limit = REDIRECTS_LIMIT
32
26
  end
33
27
 
34
- def execute_request(request)
35
-
28
+ def execute_request(request, redirects_limit = 10)
36
29
  assert_not_nil request, "Request argument cannot be null."
37
30
 
38
31
  @redirect_response = nil
@@ -47,56 +40,31 @@ module Stormpath
47
40
 
48
41
  method = @http_client.method(request.http_method.downcase)
49
42
 
50
- if request.body.nil?
51
-
52
- response = method.call domain, nil, request.http_headers
43
+ response = method.call domain, request.body, request.http_headers
53
44
 
54
- else
55
-
56
- response = method.call domain, request.body, request.http_headers
57
-
58
- end
59
-
60
- if response.redirect? and @redirects_limit > 0
45
+ if response.redirect? and redirects_limit > 0
61
46
  request.href = response.http_header['location'][0]
62
- @redirects_limit -= 1
63
- @redirect_response = execute_request request
47
+ redirects_limit -= 1
48
+ @redirect_response = execute_request request, redirects_limit
64
49
  return @redirect_response
65
50
  end
66
51
 
67
- if @redirect_response
68
- @redirects_limit = REDIRECTS_LIMIT
69
- @redirect_response
70
- else
71
- Response.new response.http_header.status_code,
52
+ Response.new response.http_header.status_code,
72
53
  response.http_header.body_type,
73
54
  response.content,
74
55
  response.http_header.body_size
75
- end
76
-
77
56
  end
78
57
 
79
58
  private
80
59
 
81
- def add_query_string href, query_string
82
-
83
- query_string.each do |key, value|
84
-
85
- if href.include? '?'
86
-
87
- href << '&' << key.to_s << '=' << value.to_s
88
-
89
- else
90
- href << '?' << key.to_s << '=' << value.to_s
60
+ def add_query_string href, query_string
61
+ query_string.each do |key, value|
62
+ prefix = if href.include? '?' then '&' else '?' end
63
+ href << prefix << key.to_s << '=' << value.to_s
91
64
  end
92
-
93
65
  end
94
66
 
95
- end
96
-
97
67
  end
98
-
99
68
  end
100
-
101
69
  end
102
70
 
@@ -13,8 +13,9 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
  #
16
- class Stormpath::Resource::Account < Stormpath::Resource::Instance
17
- include Stormpath::Resource::Status
16
+ class Stormpath::Resource::Account < Stormpath::Resource::Instance
17
+ include Stormpath::Resource::AccountStatus
18
+ include Stormpath::Resource::CustomDataStorage
18
19
 
19
20
  prop_accessor :username, :email, :given_name, :middle_name, :surname
20
21
  prop_writer :password
@@ -22,13 +23,22 @@ class Stormpath::Resource::Account < Stormpath::Resource::Instance
22
23
  prop_non_printable :password
23
24
 
24
25
  belongs_to :directory
26
+ belongs_to :tenant
27
+
25
28
  has_one :email_verification_token
26
29
 
27
30
  has_many :groups
28
31
  has_many :group_memberships
29
32
 
33
+ has_one :custom_data
34
+
30
35
  def add_group group
31
36
  client.group_memberships.create group: group, account: self
32
37
  end
33
-
38
+
39
+ def remove_group group
40
+ group_membership = group_memberships.find {|group_membership| group_membership.group.href == group.href }
41
+ group_membership.delete if group_membership
42
+ end
43
+
34
44
  end
@@ -0,0 +1,16 @@
1
+ #
2
+ # Copyright 2014 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
+ Stormpath::Resource::AccountMembership = Stormpath::Resource::GroupMembership
@@ -0,0 +1,26 @@
1
+ #
2
+ # Copyright 2014 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
+ module Stormpath::Resource::AccountStatus
17
+ include Stormpath::Resource::Status
18
+
19
+ UNVERIFIED = 'UNVERIFIED'
20
+ LOCKED = 'LOCKED'
21
+
22
+ def status_hash
23
+ super.merge UNVERIFIED => UNVERIFIED, LOCKED => LOCKED
24
+ end
25
+
26
+ end
@@ -14,7 +14,6 @@
14
14
  # limitations under the License.
15
15
  #
16
16
  class Stormpath::Resource::AccountStoreMapping < Stormpath::Resource::Instance
17
- include Stormpath::Resource::Status
18
17
 
19
18
  prop_accessor :list_index, :is_default_account_store, :is_default_group_store
20
19
 
@@ -24,9 +23,12 @@ class Stormpath::Resource::AccountStoreMapping < Stormpath::Resource::Instance
24
23
 
25
24
  alias_method :default_account_store, :is_default_account_store
26
25
  alias_method :default_account_store?, :is_default_account_store
26
+
27
+ alias_method :default_account_store=, :is_default_account_store=
28
+
27
29
  alias_method :default_group_store, :is_default_group_store
28
30
  alias_method :default_group_store?, :is_default_group_store
29
- alias_method :default_account_store=, :is_default_account_store=
31
+
30
32
  alias_method :default_group_store=, :is_default_group_store=
31
33
 
32
34
  end
@@ -21,10 +21,12 @@ class Stormpath::Resource::Application < Stormpath::Resource::Instance
21
21
  prop_accessor :name, :description
22
22
 
23
23
  belongs_to :tenant
24
- has_many :accounts, can: [:create]
24
+
25
+ has_many :accounts, can: [:get, :create]
25
26
  has_many :password_reset_tokens, can: [:get, :create]
26
27
  has_many :account_store_mappings, can: [:get, :create]
27
-
28
+ has_many :groups, can: [:get, :create]
29
+
28
30
  has_one :default_account_store_mapping, class_name: :accountStoreMapping
29
31
  has_one :default_group_store_mapping, class_name: :accountStoreMapping
30
32
 
@@ -24,7 +24,6 @@ module Stormpath
24
24
  options[:class_name] ||= name
25
25
  resource_class = "Stormpath::Resource::#{options[:class_name].to_s.camelize}".constantize
26
26
  property_name = name.to_s.camelize :lower
27
-
28
27
  define_method(name) do
29
28
  get_resource_property property_name, resource_class
30
29
  end
@@ -90,9 +89,14 @@ module Stormpath
90
89
  href = get_href_from_hash value
91
90
  end
92
91
 
93
- if href
94
- data_store.instantiate clazz, value
92
+ if instance_variable_get("@_#{key.underscore}").nil?
93
+ if href
94
+ instance_variable_set("@_#{key.underscore}", data_store.instantiate(clazz, value))
95
+ else
96
+ instance_variable_set("@_#{key.underscore}", clazz.new(value))
97
+ end
95
98
  end
99
+ instance_variable_get("@_#{key.underscore}")
96
100
  end
97
101
 
98
102
  def get_resource_href_property(key)
@@ -18,26 +18,22 @@ class Stormpath::Resource::Base
18
18
  include Stormpath::Resource::Associations
19
19
 
20
20
  HREF_PROP_NAME = "href"
21
-
21
+ DEFAULT_SERVER_HOST = Stormpath::DataStore::DEFAULT_SERVER_HOST
22
22
  attr_reader :client, :properties
23
23
 
24
24
  class << self
25
25
  def prop_reader(*args)
26
26
  args.each do |name|
27
- property_name = name.to_s.camelize :lower
28
-
29
27
  define_method(name) do
30
- get_property property_name
28
+ get_property name
31
29
  end
32
30
  end
33
31
  end
34
32
 
35
33
  def prop_writer(*args)
36
34
  args.each do |name|
37
- property_name = name.to_s.camelize :lower
38
-
39
35
  define_method("#{name.to_s}=") do |value|
40
- set_property property_name, value
36
+ set_property name, value
41
37
  end
42
38
  end
43
39
  end
@@ -79,6 +75,7 @@ class Stormpath::Resource::Base
79
75
  @write_lock = Mutex.new
80
76
  @properties = Hash.new
81
77
  @dirty_properties = Hash.new
78
+ @deleted_properties = Array.new
82
79
  set_properties properties
83
80
  end
84
81
 
@@ -106,6 +103,16 @@ class Stormpath::Resource::Base
106
103
  end
107
104
  end
108
105
 
106
+ def get_dirty_property_names
107
+ @read_lock.lock
108
+
109
+ begin
110
+ @dirty_properties.keys
111
+ ensure
112
+ @read_lock.unlock
113
+ end
114
+ end
115
+
109
116
  def set_properties properties
110
117
  @write_lock.lock
111
118
 
@@ -114,9 +121,9 @@ class Stormpath::Resource::Base
114
121
  @dirty_properties.clear
115
122
  @dirty = false
116
123
 
117
- unless properties.nil?
124
+ if properties
118
125
  @properties = deep_sanitize properties
119
-
126
+ @dirty_properties = @properties if new?
120
127
  # Don't consider this resource materialized if it is only a reference. A reference is any object that
121
128
  # has only one 'href' property.
122
129
  href_only = (@properties.size == 1 and @properties.has_key? HREF_PROP_NAME)
@@ -133,7 +140,7 @@ class Stormpath::Resource::Base
133
140
  def get_property name
134
141
  property_name = name.to_s.camelize :lower
135
142
 
136
- if !HREF_PROP_NAME.eql? property_name
143
+ if HREF_PROP_NAME != property_name
137
144
  #not the href/id, must be a property that requires materialization:
138
145
  unless new? or materialized?
139
146
 
@@ -155,7 +162,7 @@ class Stormpath::Resource::Base
155
162
  end
156
163
  end
157
164
 
158
- read_property name
165
+ read_property property_name
159
166
  end
160
167
 
161
168
  def set_property name, value
@@ -214,7 +221,7 @@ class Stormpath::Resource::Base
214
221
  private
215
222
 
216
223
  def get_href_from_hash(props)
217
- if !props.nil? and props.is_a? Hash
224
+ if props and props.is_a? Hash
218
225
  props[HREF_PROP_NAME]
219
226
  end
220
227
  end
@@ -233,10 +240,8 @@ class Stormpath::Resource::Base
233
240
  {}.tap do |sanitized_properties|
234
241
  properties.map do |key, value|
235
242
  property_name = key.to_s.camelize :lower
236
-
237
243
  sanitized_properties[property_name] =
238
- if (value.kind_of? Hash) or
239
- (value.kind_of? Stormpath::Resource::Base)
244
+ if value.kind_of? Hash or value.kind_of? Stormpath::Resource::Base
240
245
  deep_sanitize value
241
246
  else
242
247
  value
@@ -253,4 +258,5 @@ class Stormpath::Resource::Base
253
258
  sanitize hash_or_resource
254
259
  end
255
260
  end
261
+
256
262
  end
@@ -0,0 +1,86 @@
1
+ #
2
+ # Copyright 2013 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::CustomData < Stormpath::Resource::Instance
17
+ include Stormpath::Resource::CustomDataHashMethods
18
+
19
+ def [](property_name)
20
+ get_property property_name
21
+ end
22
+
23
+ def []=(property_name, property_value)
24
+ set_property property_name, property_value
25
+ end
26
+
27
+ def save
28
+ if has_removed_properties?
29
+ delete_removed_properties
30
+ end
31
+ if has_new_properties?
32
+ super
33
+ end
34
+ end
35
+
36
+ def delete(name = nil)
37
+ super() if name.nil?
38
+
39
+ @write_lock.lock
40
+ property_name = name.to_s
41
+ begin
42
+ @properties.delete(property_name)
43
+ @dirty_properties.delete(property_name)
44
+ @deleted_properties << property_name
45
+ @dirty = true
46
+ ensure
47
+ @write_lock.unlock
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def sanitize(properties)
54
+ {}.tap do |sanitized_properties|
55
+ properties.map do |key, value|
56
+ property_name = key.to_s.camelize :lower
57
+ sanitized_properties[property_name] = value
58
+ end
59
+ end
60
+ end
61
+
62
+ def has_removed_properties?
63
+ @read_lock.lock
64
+ begin
65
+ !@deleted_properties.empty?
66
+ ensure
67
+ @read_lock.unlock
68
+ end
69
+ end
70
+
71
+ def has_new_properties?
72
+ @read_lock.lock
73
+ begin
74
+ !@dirty_properties.empty?
75
+ ensure
76
+ @read_lock.unlock
77
+ end
78
+ end
79
+
80
+ def delete_removed_properties
81
+ @deleted_properties.each do |deleted_property_name|
82
+ data_store.delete self, deleted_property_name
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,33 @@
1
+ module Stormpath::Resource::CustomDataHashMethods
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ def has_key?(key)
6
+ materialize unless materialized?
7
+ properties.has_key? key.to_s.camelize(:lower)
8
+ end
9
+
10
+ alias_method :include?, :has_key?
11
+
12
+ def has_value?(value)
13
+ materialize unless materialized?
14
+ properties.has_value? value
15
+ end
16
+
17
+ def store(key, value)
18
+ materialize unless materialized?
19
+ self[key] = value
20
+ end
21
+
22
+ def keys
23
+ materialize unless materialized?
24
+ properties.keys.map {|key| key.to_s.underscore}
25
+ end
26
+
27
+ def values
28
+ materialize unless materialized?
29
+ properties.values
30
+ end
31
+ end
32
+
33
+ end