simple_crowd 1.1.3 → 1.2.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/simple_crowd.rb +0 -2
- data/lib/simple_crowd/client.rb +59 -26
- data/lib/simple_crowd/crowd_entity.rb +143 -144
- data/lib/simple_crowd/crowd_error.rb +7 -3
- data/lib/simple_crowd/group.rb +4 -3
- data/lib/simple_crowd/mock_client.rb +14 -3
- data/lib/simple_crowd/user.rb +14 -8
- data/lib/simple_crowd/version.rb +1 -1
- data/simple_crowd.gemspec +0 -1
- data/test/crowd_config.yml.example +5 -0
- data/test/factories.rb +3 -3
- data/test/test_client.rb +37 -34
- data/test/test_user.rb +30 -21
- metadata +5 -22
- data/lib/simple_crowd/mappers/soap_attributes.rb +0 -13
data/lib/simple_crowd.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'savon'
|
2
|
-
require 'hashie'
|
3
2
|
require 'yaml'
|
4
3
|
require 'forwardable'
|
5
4
|
require 'simple_crowd/crowd_entity'
|
@@ -7,7 +6,6 @@ require 'simple_crowd/crowd_error'
|
|
7
6
|
require 'simple_crowd/user'
|
8
7
|
require 'simple_crowd/group'
|
9
8
|
require 'simple_crowd/client'
|
10
|
-
require 'simple_crowd/mappers/soap_attributes'
|
11
9
|
require 'simple_crowd/cache/null_store'
|
12
10
|
Dir['simple_crowd/mappers/*.rb'].each {|file| require File.basename(file, File.extname(file)) }
|
13
11
|
|
data/lib/simple_crowd/client.rb
CHANGED
@@ -82,7 +82,7 @@ module SimpleCrowd
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def find_group_by_name name
|
85
|
-
SimpleCrowd::Group.
|
85
|
+
SimpleCrowd::Group.from_soap simple_soap_call(:find_group_by_name, name)
|
86
86
|
end
|
87
87
|
|
88
88
|
def find_all_group_names
|
@@ -114,15 +114,15 @@ module SimpleCrowd
|
|
114
114
|
end
|
115
115
|
|
116
116
|
def find_user_by_name name
|
117
|
-
SimpleCrowd::User.
|
117
|
+
SimpleCrowd::User.from_soap simple_soap_call(:find_principal_by_name, name) rescue nil
|
118
118
|
end
|
119
119
|
|
120
120
|
def find_user_with_attributes_by_name name
|
121
|
-
SimpleCrowd::User.
|
121
|
+
SimpleCrowd::User.from_soap simple_soap_call(:find_principal_with_attributes_by_name, name) rescue nil
|
122
122
|
end
|
123
123
|
|
124
124
|
def find_user_by_token token
|
125
|
-
SimpleCrowd::User.
|
125
|
+
SimpleCrowd::User.from_soap simple_soap_call(:find_principal_by_token, token) rescue nil
|
126
126
|
end
|
127
127
|
|
128
128
|
def find_username_by_token token
|
@@ -137,15 +137,31 @@ module SimpleCrowd
|
|
137
137
|
|
138
138
|
# Partial email match
|
139
139
|
def search_users_by_email email
|
140
|
-
search_users({'
|
141
|
-
end
|
142
|
-
|
143
|
-
|
144
|
-
|
140
|
+
search_users({'email' => email})
|
141
|
+
end
|
142
|
+
|
143
|
+
# Search Crowd users using the given criteria.
|
144
|
+
#
|
145
|
+
# critieria should be a hash of SimpleCrowd::User properties or attributes.
|
146
|
+
# Not all properties are supported, see (https://developer.atlassian.com/display/CROWDDEV/Using+the+Search+API)
|
147
|
+
#
|
148
|
+
# NOTE: Atlassian Crowd contains a bug that ignores the limit and start
|
149
|
+
# parameters
|
150
|
+
#
|
151
|
+
# For example:
|
152
|
+
# client.search_users(:email => 'foo', :display_name => 'bar')
|
153
|
+
def search_users criteria, limit=0, start=0
|
154
|
+
# Convert search criteria to Crowd search restrictions
|
155
|
+
restrictions = criteria.inject({}) do |h, (key, val)|
|
156
|
+
key = User.search_restriction_for(key).to_s
|
157
|
+
h[key] = val
|
158
|
+
h
|
159
|
+
end
|
160
|
+
soap_restrictions = add_soap_namespace(prepare_search_restrictions(restrictions, limit, start))
|
145
161
|
users = simple_soap_call :search_principals, soap_restrictions rescue []
|
146
162
|
return [] if users.nil? || users[:soap_principal].nil?
|
147
163
|
users = users[:soap_principal].is_a?(Array) ? users[:soap_principal] : [users[:soap_principal]]
|
148
|
-
users.map{|u| SimpleCrowd::User.
|
164
|
+
users.map{|u| SimpleCrowd::User.from_soap u}
|
149
165
|
end
|
150
166
|
|
151
167
|
def add_user user, credential
|
@@ -153,15 +169,16 @@ module SimpleCrowd
|
|
153
169
|
[:email, :first_name, :last_name].each do |k|
|
154
170
|
user.send(:"#{k}=", "") if user.send(k).nil?
|
155
171
|
end
|
156
|
-
soap_user = user.
|
172
|
+
soap_user = user.to_soap
|
157
173
|
# We don't use these attributes when creating
|
158
174
|
soap_user.delete(:id)
|
159
175
|
soap_user.delete(:directory_id)
|
160
176
|
# Add blank attributes if missing
|
161
177
|
|
162
178
|
# Declare require namespaces
|
163
|
-
soap_user = soap_user
|
164
|
-
|
179
|
+
soap_user = add_soap_namespace(soap_user)
|
180
|
+
|
181
|
+
SimpleCrowd::User.from_soap simple_soap_call(:add_principal, soap_user, {'auth:credential' => credential, 'auth:encryptedCredential' => false})
|
165
182
|
end
|
166
183
|
|
167
184
|
def remove_user name
|
@@ -182,8 +199,8 @@ module SimpleCrowd
|
|
182
199
|
# @param value [String] of attribute to update
|
183
200
|
def update_user_attribute user, name, value
|
184
201
|
return unless (name.is_a?(String) || name.is_a?(Symbol)) && (value.is_a?(String) || value.is_a?(Array))
|
185
|
-
soap_attr =
|
186
|
-
simple_soap_call :update_principal_attribute, user, soap_attr
|
202
|
+
soap_attr = add_soap_namespace({:name => name, :values => {:string => value}})
|
203
|
+
simple_soap_call :update_principal_attribute, user, soap_attr
|
187
204
|
true
|
188
205
|
end
|
189
206
|
alias_method :add_user_attribute, :update_user_attribute
|
@@ -196,10 +213,11 @@ module SimpleCrowd
|
|
196
213
|
return if attrs_to_update.empty?
|
197
214
|
|
198
215
|
attrs_to_update.each do |a|
|
199
|
-
|
200
|
-
|
201
|
-
self.update_user_attribute user.username, soap_prop, user.send(a)
|
216
|
+
key = SimpleCrowd::User.soap_key_for(a)
|
217
|
+
self.update_user_attribute user.username, key, user.send(a)
|
202
218
|
end
|
219
|
+
user.clean
|
220
|
+
user
|
203
221
|
end
|
204
222
|
|
205
223
|
def app_token
|
@@ -266,10 +284,8 @@ module SimpleCrowd
|
|
266
284
|
old_raise_errors = client.config.raise_errors
|
267
285
|
client.config.raise_errors = true
|
268
286
|
yield
|
269
|
-
rescue Savon::SOAP::Fault =>
|
270
|
-
raise CrowdError.new(
|
271
|
-
rescue Savon::HTTP::Error => e
|
272
|
-
raise CrowdError.new(e.to_s)
|
287
|
+
rescue Savon::SOAP::Fault, Savon::HTTP::Error => e
|
288
|
+
raise CrowdError.new(e)
|
273
289
|
ensure
|
274
290
|
client.config.raise_errors = old_raise_errors
|
275
291
|
end
|
@@ -324,10 +340,13 @@ module SimpleCrowd
|
|
324
340
|
}
|
325
341
|
end
|
326
342
|
|
327
|
-
def prepare_search_restrictions restrictions
|
328
|
-
|
329
|
-
|
330
|
-
|
343
|
+
def prepare_search_restrictions restrictions, limit=0, start=0
|
344
|
+
restrictions = restrictions.inject([]) do |arr, (key, val)|
|
345
|
+
arr << {'name' => key, 'value' => val}
|
346
|
+
end
|
347
|
+
restrictions << {'name' => 'search.max.results', 'value' => limit.to_i} if limit.to_i > 0
|
348
|
+
restrictions << {'name' => 'search.index.start', 'value' => start.to_i} if start.to_i > 0
|
349
|
+
{'searchRestriction' => restrictions}
|
331
350
|
end
|
332
351
|
|
333
352
|
def hash_authenticated_token name = @options[:app_name], token = nil
|
@@ -342,5 +361,19 @@ module SimpleCrowd
|
|
342
361
|
def cache_key(key)
|
343
362
|
"#{@options[:cache_prefix]}#{key}"
|
344
363
|
end
|
364
|
+
|
365
|
+
def add_soap_namespace(enum)
|
366
|
+
if enum.is_a?(Hash)
|
367
|
+
enum.inject({}) do |h, (k, v)|
|
368
|
+
k = k == :string ? "wsdl:#{k}" : "int:#{k}"
|
369
|
+
h[k] = v.is_a?(Enumerable) ? add_soap_namespace(v) : v
|
370
|
+
h
|
371
|
+
end
|
372
|
+
else
|
373
|
+
enum.map do |v|
|
374
|
+
v.is_a?(Enumerable) ? add_soap_namespace(v) : v
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
345
378
|
end
|
346
379
|
end
|
@@ -1,199 +1,198 @@
|
|
1
1
|
module SimpleCrowd
|
2
|
-
class
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
property :maps, :default => {}
|
8
|
-
property :mappers, :default => {}
|
9
|
-
def immutable?; @immutable; end
|
10
|
-
def is_attribute?; @attribute end
|
11
|
-
end
|
12
|
-
class CrowdEntity < Hashie::Mash
|
13
|
-
def initialize(data = {}, notused = nil)
|
14
|
-
self.class.properties.each do |prop|
|
15
|
-
self.send("#{prop.name}=", self.class.defaults[prop.name.to_sym])
|
2
|
+
class CrowdEntity
|
3
|
+
|
4
|
+
def initialize(attrs={})
|
5
|
+
self.class.defaults.each do |key, val|
|
6
|
+
send(:"#{key.to_s}=", val)
|
16
7
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
data.each_pair do |att, value|
|
21
|
-
#ruby_att = att_to_ruby att
|
22
|
-
ruby_att = att
|
23
|
-
real_att = real_key_for ruby_att
|
24
|
-
(@attributes ||= []) << real_att if attrs.include?(att)
|
25
|
-
prop = self.class.property_by_name(real_att)
|
26
|
-
self.send("#{real_att}=", value) unless prop.nil?
|
27
|
-
self[real_att] = value if prop.nil?
|
8
|
+
|
9
|
+
attrs.each do |key, val|
|
10
|
+
send(:"#{key.to_s}=", val) if self.respond_to?("#{key.to_s}=", true)
|
28
11
|
end
|
29
|
-
# We just initialized the attributes so clear the dirty status
|
30
12
|
dirty_properties.clear
|
31
13
|
end
|
32
|
-
|
14
|
+
|
15
|
+
def self.property(property_name, opts={})
|
33
16
|
property_name = property_name.to_sym
|
34
17
|
|
35
|
-
|
36
|
-
|
37
|
-
options.reject! {|key, val| key.to_s =~ /^map_(.*)$/ || key.to_s =~ /^mapper_(.*)$/ }
|
38
|
-
(@properties ||= []) << ExtendedProperty.new({:name => property_name, :maps => maps, :mappers => mappers}.merge(options))
|
39
|
-
(@attributes ||= []) << property_name if options[:attribute]
|
18
|
+
@properties ||= []
|
19
|
+
@properties << property_name unless @properties.include?(property_name)
|
40
20
|
|
41
|
-
class_eval <<-
|
21
|
+
class_eval <<-PROPERTY, __FILE__, __LINE__ + 1
|
42
22
|
def #{property_name}
|
43
|
-
|
23
|
+
@#{property_name}
|
44
24
|
end
|
45
25
|
def #{property_name}=(val)
|
46
|
-
(dirty_properties << :#{property_name}).uniq! unless val ==
|
47
|
-
|
26
|
+
(dirty_properties << :#{property_name}).uniq! unless val == @#{property_name}
|
27
|
+
@#{property_name} = val
|
48
28
|
end
|
49
|
-
|
29
|
+
PROPERTY
|
50
30
|
|
51
|
-
|
52
|
-
|
53
|
-
alias_method :"#{v}=", :"#{property_name}="
|
31
|
+
if opts[:immutable]
|
32
|
+
private :"#{property_name}="
|
54
33
|
end
|
55
|
-
end
|
56
34
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
35
|
+
if opts[:map_soap]
|
36
|
+
v = :"#{opts[:map_soap]}"
|
37
|
+
@soap_to_property_map ||= {}
|
38
|
+
@property_to_soap_map ||= {}
|
39
|
+
@soap_to_property_map[v] = property_name
|
40
|
+
@property_to_soap_map[property_name] = v
|
63
41
|
end
|
64
42
|
|
65
|
-
|
43
|
+
if opts[:search_restriction]
|
44
|
+
@property_to_search_restriction_map ||= {}
|
45
|
+
@property_to_search_restriction_map[property_name] = opts[:search_restriction]
|
46
|
+
end
|
47
|
+
|
48
|
+
if opts[:default]
|
49
|
+
@defaults ||= {}
|
50
|
+
@defaults[property_name] = opts[:default]
|
51
|
+
end
|
66
52
|
end
|
67
53
|
|
68
|
-
def self.
|
69
|
-
|
70
|
-
|
54
|
+
def self.attribute(attr_name, opts={})
|
55
|
+
attr_name = attr_name.to_sym
|
56
|
+
@attributes ||= []
|
57
|
+
@attributes << attr_name
|
58
|
+
self.property(attr_name, opts)
|
71
59
|
end
|
72
60
|
|
73
|
-
def self.
|
74
|
-
|
75
|
-
properties.select {|p| p.name == property_name || p.maps.value?(property_name)}
|
61
|
+
def self.properties
|
62
|
+
@properties.freeze
|
76
63
|
end
|
77
64
|
|
78
|
-
def self.
|
79
|
-
|
65
|
+
def self.attributes
|
66
|
+
@attributes.freeze
|
80
67
|
end
|
81
68
|
|
82
69
|
def self.defaults
|
83
|
-
|
70
|
+
@defaults.freeze
|
84
71
|
end
|
85
72
|
|
86
|
-
def
|
87
|
-
@
|
88
|
-
unless hash.nil?
|
89
|
-
@attribute_mappers.merge! hash if hash.is_a? Hash
|
90
|
-
end
|
91
|
-
@attribute_mappers
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.map_for type
|
95
|
-
type = type.to_sym
|
96
|
-
properties.inject({}) {|hash, prop| hash[prop.name] = prop.maps[type] unless prop.maps[type].nil?; hash }
|
97
|
-
end
|
98
|
-
|
99
|
-
def self.map_to type, entity
|
100
|
-
map = map_for type
|
101
|
-
attrs = {}
|
102
|
-
out = entity.inject({}) do |hash, (key, val)|
|
103
|
-
key = key.to_sym
|
104
|
-
catch(:skip_prop) do
|
105
|
-
unless val.nil?
|
106
|
-
mapped_key = map[key].nil? ? key : map[key]
|
107
|
-
prop = property_by_name key
|
108
|
-
if prop.nil?
|
109
|
-
attrs[mapped_key] = val
|
110
|
-
throw :skip_prop
|
111
|
-
end
|
112
|
-
mapper = prop.mappers[type]
|
113
|
-
#val = val.inject({}) {|attrs, (k, v)| attrs[property_by_name(k).maps[type]]= v unless v.nil?; attrs} if key == :attributes
|
114
|
-
val = mapper.produce val unless mapper.nil?
|
115
|
-
if prop.attribute || entity.attributes_keys.include?(key)
|
116
|
-
attrs[mapped_key] = val
|
117
|
-
else
|
118
|
-
hash[mapped_key] = val
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
hash
|
123
|
-
end
|
124
|
-
out[:attributes] = attribute_mappers[type].produce attrs
|
125
|
-
out
|
73
|
+
def dirty_properties
|
74
|
+
@dirty_properties ||= Array.new
|
126
75
|
end
|
127
76
|
|
128
|
-
def
|
129
|
-
|
130
|
-
parsed_entity = entity.inject({}) do |hash, (key, val)|
|
131
|
-
prop = property_by_name key
|
132
|
-
unless prop.nil?
|
133
|
-
mapper = prop.mappers[type]
|
134
|
-
val = mapper.parse val unless mapper.nil?
|
135
|
-
end
|
136
|
-
hash[key] = val
|
137
|
-
hash
|
138
|
-
end
|
139
|
-
self.new(parsed_entity)
|
77
|
+
def dirty_attributes
|
78
|
+
dirty_properties & self.class.attributes
|
140
79
|
end
|
141
80
|
|
142
|
-
def
|
143
|
-
|
81
|
+
def dirty?(prop=nil)
|
82
|
+
prop.nil? ? !@dirty_properties.empty? : @dirty_properties.include?(prop)
|
144
83
|
end
|
145
84
|
|
146
|
-
def
|
147
|
-
|
148
|
-
|
149
|
-
if
|
150
|
-
keys << elder.instance_variable_get("@attributes")
|
151
|
-
end
|
85
|
+
def update(properties_and_attributes)
|
86
|
+
return unless properties_and_attributes
|
87
|
+
properties_and_attributes.each do |key, val|
|
88
|
+
send(:"#{key.to_s}=", val) if self.respond_to?("#{key.to_s}=")
|
152
89
|
end
|
153
|
-
keys << @attributes unless @attributes.nil?
|
154
|
-
keys.flatten.uniq
|
155
90
|
end
|
156
91
|
|
157
|
-
def
|
158
|
-
|
92
|
+
def clean
|
93
|
+
@dirty_properties.clear
|
94
|
+
end
|
95
|
+
|
96
|
+
def [](key)
|
97
|
+
respond_to?(:"#{key}") ? send(:"#{key}") : nil
|
159
98
|
end
|
160
99
|
|
161
|
-
def
|
162
|
-
|
100
|
+
def valid?
|
101
|
+
errors.empty?
|
163
102
|
end
|
164
103
|
|
165
|
-
def
|
166
|
-
|
104
|
+
def errors
|
105
|
+
{}
|
167
106
|
end
|
168
107
|
|
169
|
-
def
|
170
|
-
|
108
|
+
def to_hash
|
109
|
+
(self.class.properties || []).inject({}) do |hash, key|
|
110
|
+
hash[key] = send(key) if respond_to?(key)
|
111
|
+
hash
|
112
|
+
end
|
171
113
|
end
|
172
114
|
|
173
|
-
def
|
174
|
-
|
115
|
+
def inspect
|
116
|
+
ret = "#<#{self.class.to_s}"
|
117
|
+
self.class.properties.each do |key|
|
118
|
+
ret << " #{key}=#{self.instance_variable_get("@#{key}").inspect}"
|
119
|
+
end
|
120
|
+
ret << ">"
|
121
|
+
ret
|
175
122
|
end
|
176
123
|
|
177
|
-
def
|
178
|
-
|
179
|
-
|
124
|
+
def self.from_soap(data)
|
125
|
+
data = data.dup if data
|
126
|
+
|
127
|
+
# Merge attributes into the main hash
|
128
|
+
if data && data[:attributes] && data[:attributes][:soap_attribute]
|
129
|
+
attrs = {}
|
130
|
+
attrs = data[:attributes][:soap_attribute].inject({}) do |hash, attr|
|
131
|
+
hash[attr[:name]] = attr[:values][:string]
|
132
|
+
hash
|
133
|
+
end
|
134
|
+
data.delete :attributes
|
135
|
+
data.merge! attrs
|
136
|
+
end
|
137
|
+
|
138
|
+
# Clean soap values
|
139
|
+
data.each do |(key, val)|
|
140
|
+
if val.is_a?(Hash) && val[:"@xmlns"]
|
141
|
+
val.delete(:"@xmlns")
|
142
|
+
data[key] = nil if val.empty?
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Map soap values to property values
|
147
|
+
if @soap_to_property_map
|
148
|
+
data = data.inject({}) do |hash, (key, val)|
|
149
|
+
key = :"#{key}"
|
150
|
+
if @soap_to_property_map.has_key?(key)
|
151
|
+
hash[@soap_to_property_map[key]] = val
|
152
|
+
else
|
153
|
+
hash[key] = val
|
154
|
+
end
|
155
|
+
hash
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
self.new data
|
180
160
|
end
|
181
161
|
|
182
|
-
def
|
183
|
-
|
184
|
-
|
185
|
-
|
162
|
+
def to_soap
|
163
|
+
properties = self.class.properties || []
|
164
|
+
attributes = self.class.attributes || []
|
165
|
+
|
166
|
+
data = {}
|
167
|
+
data[:attributes] = {:SOAPAttribute => []} unless attributes.empty?
|
168
|
+
properties.each do |prop|
|
169
|
+
key = self.class.soap_key_for(prop)
|
170
|
+
val = send(prop)
|
171
|
+
|
172
|
+
if attributes.include?(prop)
|
173
|
+
data[:attributes][:SOAPAttribute] << {:name => key, :values => {:string => val}}
|
174
|
+
else
|
175
|
+
data[key] = val
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
data
|
186
180
|
end
|
187
181
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
182
|
+
def self.soap_key_for(property_key)
|
183
|
+
property_key = :"#{property_key}"
|
184
|
+
if @property_to_soap_map && @property_to_soap_map.has_key?(property_key)
|
185
|
+
return @property_to_soap_map[property_key]
|
186
|
+
end
|
187
|
+
property_key
|
192
188
|
end
|
193
|
-
|
194
|
-
|
189
|
+
|
190
|
+
def self.search_restriction_for(property_key)
|
191
|
+
property_key = :"#{property_key}"
|
192
|
+
if @property_to_search_restriction_map && @property_to_search_restriction_map.has_key?(property_key)
|
193
|
+
return @property_to_search_restriction_map[property_key]
|
194
|
+
end
|
195
|
+
property_key
|
195
196
|
end
|
196
|
-
def real_key_for att; self.class.real_key_for att; end
|
197
|
-
def att_to_ruby att; self.class.att_to_ruby att; end
|
198
197
|
end
|
199
198
|
end
|
@@ -4,17 +4,21 @@ module SimpleCrowd
|
|
4
4
|
attr_reader :type
|
5
5
|
attr_reader :original
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
super string
|
7
|
+
def initialize(original, message=nil)
|
9
8
|
@original = original
|
10
9
|
|
11
10
|
if original.is_a?(Savon::SOAP::Fault)
|
11
|
+
fault = original.to_hash[:fault] || {}
|
12
12
|
@response = original.http
|
13
|
-
@type =
|
13
|
+
@type = fault[:detail].keys.first rescue :fault
|
14
|
+
message = fault[:faultstring] if message.blank?
|
14
15
|
elsif original.is_a?(Savon::HTTP::Error)
|
15
16
|
@response = original.http
|
16
17
|
@type = :http
|
17
18
|
end
|
19
|
+
|
20
|
+
message = original.to_s if message.blank?
|
21
|
+
super message
|
18
22
|
end
|
19
23
|
|
20
24
|
def type? type
|
data/lib/simple_crowd/group.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module SimpleCrowd
|
2
2
|
class Group < CrowdEntity
|
3
|
-
property :id
|
4
|
-
property :name
|
3
|
+
property :id, :immutable => true
|
4
|
+
property :name, :immutable => true
|
5
|
+
property :directory_id, :immutable => true
|
6
|
+
|
5
7
|
property :active, :default => true
|
6
8
|
property :description
|
7
|
-
property :directory_id
|
8
9
|
|
9
10
|
property :members
|
10
11
|
end
|
@@ -23,7 +23,7 @@ module SimpleCrowd
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def authenticate_user name, password, factors = nil
|
26
|
-
(user = find_user_by_name(name)) && user.password && user.password == password ? new_user_token(name) : nil
|
26
|
+
(user = find_user_by_name(name)) && user.instance_variable_get('@password') && user.instance_variable_get('@password') == password ? new_user_token(name) : nil
|
27
27
|
end
|
28
28
|
def create_user_token name
|
29
29
|
new_user_token(name) if find_user_by_name(name)
|
@@ -54,9 +54,19 @@ module SimpleCrowd
|
|
54
54
|
def search_users_by_email email
|
55
55
|
users.select{|u| u.email =~ /#{email}/}
|
56
56
|
end
|
57
|
+
def search_users criteria, limit=0, start=0
|
58
|
+
users = users()
|
59
|
+
criteria.each do |search_key, search_val|
|
60
|
+
users = users.select do |user|
|
61
|
+
val = user[:"#{search_key}"]
|
62
|
+
val && val.downcase.include?(search_val.downcase)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
users
|
66
|
+
end
|
57
67
|
def add_user user, credential
|
58
68
|
if user && user.username && !find_user_by_name(user.username)
|
59
|
-
user.password
|
69
|
+
user.instance_variable_set('@password', credential)
|
60
70
|
self.class.users << user
|
61
71
|
user
|
62
72
|
end
|
@@ -67,7 +77,7 @@ module SimpleCrowd
|
|
67
77
|
end
|
68
78
|
def update_user_credential name, credential, encrypted = false
|
69
79
|
if user = find_user_by_name(name)
|
70
|
-
user.password
|
80
|
+
user.instance_variable_set('@password', credential)
|
71
81
|
end
|
72
82
|
end
|
73
83
|
def update_user_attribute user, name, value
|
@@ -87,6 +97,7 @@ module SimpleCrowd
|
|
87
97
|
attrs_to_update.each do |a|
|
88
98
|
stored_user[a] = user.send(a)
|
89
99
|
end
|
100
|
+
user.clean
|
90
101
|
end
|
91
102
|
|
92
103
|
def is_group_member? group, user
|
data/lib/simple_crowd/user.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
module SimpleCrowd
|
2
2
|
class User < CrowdEntity
|
3
|
-
|
4
3
|
# Immutable properties
|
5
4
|
property :id, :immutable => true
|
6
5
|
property :username, :immutable => true, :map_soap => :name
|
7
|
-
property :
|
8
|
-
|
9
|
-
property :
|
6
|
+
property :directory_id, :immutable => true, :search_restriction => 'principal.directory.id'
|
7
|
+
|
8
|
+
property :active, :default => true, :search_restriction => 'principal.active'
|
9
|
+
property :description
|
10
10
|
|
11
11
|
# Assumed available attributes (with soap aliases)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
attribute :first_name, :map_soap => :givenName
|
13
|
+
attribute :last_name, :map_soap => :sn
|
14
|
+
attribute :display_name, :map_soap => :displayName, :search_restriction => 'principal.fullname'
|
15
|
+
attribute :email, :map_soap => :mail, :search_restriction => 'principal.email'
|
16
|
+
|
17
|
+
def errors
|
18
|
+
errors = super
|
19
|
+
errors[:username] = "cannot be blank" if username.to_s == ""
|
20
|
+
errors
|
21
|
+
end
|
16
22
|
end
|
17
23
|
end
|
data/lib/simple_crowd/version.rb
CHANGED
data/simple_crowd.gemspec
CHANGED
@@ -19,7 +19,6 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
21
|
s.add_runtime_dependency(%q<savon>, [">= 1.0.0"])
|
22
|
-
s.add_runtime_dependency(%q<hashie>, [">= 1.0.0"])
|
23
22
|
|
24
23
|
s.add_development_dependency(%q<bundler>, [">= 1.0.21"])
|
25
24
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
data/test/factories.rb
CHANGED
@@ -3,9 +3,9 @@ FactoryGirl.define do
|
|
3
3
|
first_name 'Test'
|
4
4
|
last_name 'User'
|
5
5
|
display_name {|a| "#{a.first_name} #{a.last_name}"}
|
6
|
-
email {|a| "#{a.first_name}.#{a.last_name}@
|
7
|
-
sequence(:username) {|n| "
|
6
|
+
email {|a| "#{a.first_name}.#{a.last_name}@testing.com".downcase }
|
7
|
+
sequence(:username) {|n| "testadd#{n}" }
|
8
8
|
# Clear dirty properties
|
9
|
-
|
9
|
+
after(:build) { |user| user.dirty_properties.clear }
|
10
10
|
end
|
11
11
|
end
|
data/test/test_client.rb
CHANGED
@@ -2,10 +2,10 @@ require 'helper'
|
|
2
2
|
|
3
3
|
class TestClient < Test::Unit::TestCase
|
4
4
|
CROWD_CONFIG = YAML.load_file($CROWD_CONFIG_PATH)['crowd']
|
5
|
-
TEST_USER=
|
6
|
-
TEST_PASSWORD=
|
7
|
-
TEST_GROUP=
|
8
|
-
TEST_EMAIL=
|
5
|
+
TEST_USER = CROWD_CONFIG['test_user']
|
6
|
+
TEST_PASSWORD = CROWD_CONFIG['test_pass']
|
7
|
+
TEST_GROUP = CROWD_CONFIG['test_group']
|
8
|
+
TEST_EMAIL = CROWD_CONFIG['test_email']
|
9
9
|
context "A Client" do
|
10
10
|
setup do
|
11
11
|
@client = SimpleCrowd::Client.new({:service_url => CROWD_CONFIG['service_url'],
|
@@ -133,8 +133,9 @@ class TestClient < Test::Unit::TestCase
|
|
133
133
|
should "find user by name" do
|
134
134
|
user = @client.find_user_by_name TEST_USER
|
135
135
|
user.should_not be nil
|
136
|
-
[:id, :username, :
|
137
|
-
|
136
|
+
[:id, :username, :active, :directory_id, :first_name, :last_name, :email].each do |key|
|
137
|
+
user.send(key).should_not be nil
|
138
|
+
end
|
138
139
|
assert_requested :post, @service_url, :times => 2
|
139
140
|
end
|
140
141
|
should "find user by token" do
|
@@ -161,7 +162,7 @@ class TestClient < Test::Unit::TestCase
|
|
161
162
|
user.last_name.should == "User"
|
162
163
|
|
163
164
|
# partial searches should return nothing
|
164
|
-
user = @client.find_user_by_email TEST_EMAIL
|
165
|
+
user = @client.find_user_by_email TEST_EMAIL[0..-5]
|
165
166
|
user.should be nil
|
166
167
|
|
167
168
|
assert_requested :post, @service_url, :times => 3
|
@@ -222,33 +223,35 @@ class TestClient < Test::Unit::TestCase
|
|
222
223
|
updateduser.first_name.should == 'UpdatedFirst'
|
223
224
|
@client.remove_user username
|
224
225
|
end
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
226
|
+
# TODO: Implement!
|
227
|
+
#should "update user custom attribute" do
|
228
|
+
# username = "test_update"
|
229
|
+
# localuser = FactoryGirl.build(:user, :username => username)
|
230
|
+
# remoteuser = @client.add_user(localuser, "updatepass")
|
231
|
+
# @client.update_user_attribute(username, 'customAttr', 'customVal').should be true
|
232
|
+
# remoteuser = @client.find_user_with_attributes_by_name username
|
233
|
+
# remoteuser.last_name.should == localuser.last_name
|
234
|
+
#
|
235
|
+
# remoteuser[:customAttr].should == 'customVal'
|
236
|
+
# @client.remove_user username
|
237
|
+
#end
|
238
|
+
# TODO: Implement!
|
239
|
+
#should "update user attribute array" do
|
240
|
+
# username = "test_update"
|
241
|
+
# localuser = FactoryGirl.build(:user, :username => username)
|
242
|
+
# remoteuser = @client.add_user(localuser, "updatepass")
|
243
|
+
# test_array = ["one", "two", "4"]
|
244
|
+
# @client.update_user_attribute(username, 'arrayTest', test_array).should be true
|
245
|
+
# remoteuser = @client.find_user_with_attributes_by_name username
|
246
|
+
# remoteuser.last_name.should == localuser.last_name
|
247
|
+
# remoteuser[:arrayTest].sort.should == test_array.sort
|
248
|
+
# test_array.delete "two"
|
249
|
+
# @client.update_user_attribute(username, 'arrayTest', test_array).should be true
|
250
|
+
# remoteuser = @client.find_user_with_attributes_by_name username
|
251
|
+
# remoteuser[:arrayTest].sort.should == test_array.sort
|
252
|
+
# remoteuser[:arrayTest].include?("two").should be false
|
253
|
+
# @client.remove_user username
|
254
|
+
#end
|
252
255
|
should "update user" do
|
253
256
|
username = "test_update"
|
254
257
|
localuser = FactoryGirl.build(:user, :username => username)
|
data/test/test_user.rb
CHANGED
@@ -22,12 +22,13 @@ class TestUser < Test::Unit::TestCase
|
|
22
22
|
|
23
23
|
should "test attributes" do
|
24
24
|
@user.first_name = "Blah"
|
25
|
-
@user.givenName.should == "Blah"
|
26
25
|
end
|
27
26
|
|
28
27
|
should "update with" do
|
29
28
|
@user.dirty?.should be false
|
30
|
-
@user.
|
29
|
+
@user.first_name = @user.first_name
|
30
|
+
@user.dirty?.should be false
|
31
|
+
@user.last_name = "Updated"
|
31
32
|
@user.dirty?.should be true
|
32
33
|
@user.dirty_properties.length.should == 1
|
33
34
|
@user.dirty?(:last_name).should be true
|
@@ -35,34 +36,42 @@ class TestUser < Test::Unit::TestCase
|
|
35
36
|
end
|
36
37
|
|
37
38
|
should "map to soap" do
|
38
|
-
soap_user = @user.
|
39
|
+
soap_user = @user.to_soap
|
39
40
|
soap_user.should_not be nil
|
40
|
-
soap_user[:attributes].key?(
|
41
|
-
soap_user[:attributes][
|
41
|
+
soap_user[:attributes].key?(:SOAPAttribute).should be true
|
42
|
+
soap_user[:attributes][:SOAPAttribute].length.should == @user.class.attributes.length
|
42
43
|
soap_user[:name].should == @user.username
|
43
|
-
soap_user[:attributes][
|
44
|
+
soap_user[:attributes][:SOAPAttribute].select{|a|a[:name] == :mail}[0][:values][:string].should == @user.email
|
44
45
|
end
|
45
46
|
should "parse from soap" do
|
46
|
-
soap_user = {
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
soap_user = {
|
48
|
+
:id=>"-1",
|
49
|
+
:active=>true,
|
50
|
+
:attributes=>{
|
51
|
+
:soap_attribute=>[
|
52
|
+
{:name=>"givenName", :values=>{:string=>"parsefirstname"}},
|
53
|
+
{:name=>"sn", :values=>{:string=>"parselastname"}},
|
54
|
+
{:name=>"displayName", :values=>{:string=>"parsedisplayname"}},
|
55
|
+
{:name=>"mail", :values=>{:string=>"test@thinkwell.com"}},
|
56
|
+
{:name=>"customAttr", :values=>{:string => ["custom1", "custom2"]}}
|
57
|
+
],
|
58
|
+
:@xmlns=>"http://soap.integration.crowd.atlassian.com"
|
59
|
+
},
|
60
|
+
:description=>{:@xmlns=>"http://soap.integration.crowd.atlassian.com"},
|
61
|
+
:directory_id=>"32769",
|
62
|
+
:name=>"testparse"
|
63
|
+
}
|
64
|
+
|
65
|
+
obj_user = SimpleCrowd::User.from_soap soap_user
|
53
66
|
obj_user.should_not be_nil
|
54
67
|
obj_user.active.should == true
|
55
68
|
obj_user.first_name.should == "parsefirstname"
|
56
69
|
obj_user.last_name.should == "parselastname"
|
57
70
|
obj_user.display_name.should == "parsedisplayname"
|
58
|
-
obj_user.
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
should "mark new props as atttributes" do
|
63
|
-
curr_attributes = @user.attributes_keys
|
64
|
-
@user[:new_prop] = "new value"
|
65
|
-
(@user.attributes_keys - curr_attributes).should == [:new_prop]
|
71
|
+
obj_user.email.should == "test@thinkwell.com"
|
72
|
+
obj_user.description.should be_nil
|
73
|
+
#obj_user.customAttr.should == ["custom1", "custom2"]
|
74
|
+
#(obj_user.attributes_keys - [:first_name, :last_name, :display_name, :customAttr, :email]).empty?.should be true
|
66
75
|
end
|
67
76
|
|
68
77
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_crowd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.2.0.beta2
|
5
|
+
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Paul Strong
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: savon
|
@@ -27,22 +27,6 @@ dependencies:
|
|
27
27
|
- - ! '>='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 1.0.0
|
30
|
-
- !ruby/object:Gem::Dependency
|
31
|
-
name: hashie
|
32
|
-
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
|
-
requirements:
|
35
|
-
- - ! '>='
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
version: 1.0.0
|
38
|
-
type: :runtime
|
39
|
-
prerelease: false
|
40
|
-
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
|
-
requirements:
|
43
|
-
- - ! '>='
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
version: 1.0.0
|
46
30
|
- !ruby/object:Gem::Dependency
|
47
31
|
name: bundler
|
48
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,7 +77,6 @@ files:
|
|
93
77
|
- lib/simple_crowd/crowd_entity.rb
|
94
78
|
- lib/simple_crowd/crowd_error.rb
|
95
79
|
- lib/simple_crowd/group.rb
|
96
|
-
- lib/simple_crowd/mappers/soap_attributes.rb
|
97
80
|
- lib/simple_crowd/mock_client.rb
|
98
81
|
- lib/simple_crowd/user.rb
|
99
82
|
- lib/simple_crowd/version.rb
|
@@ -119,9 +102,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
119
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
103
|
none: false
|
121
104
|
requirements:
|
122
|
-
- - ! '
|
105
|
+
- - ! '>'
|
123
106
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
107
|
+
version: 1.3.1
|
125
108
|
requirements: []
|
126
109
|
rubyforge_project: simple_crowd
|
127
110
|
rubygems_version: 1.8.24
|
@@ -1,13 +0,0 @@
|
|
1
|
-
module SimpleCrowd
|
2
|
-
module Mappers
|
3
|
-
class SoapAttributes
|
4
|
-
def self.produce hash
|
5
|
-
{"int:SOAPAttribute" => hash.inject([]) {|attrs, (key, val)| attrs << {"int:name" => key, "int:values" => {"wsdl:string" => val}}}}
|
6
|
-
end
|
7
|
-
def self.parse attributes
|
8
|
-
soap = attributes[:soap_attribute]
|
9
|
-
(soap && soap.inject({}) {|hash, attr| hash[attr[:name].to_sym] = attr[:values][:string]; hash }) || {}
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|