rubysync 0.0.3 → 0.0.4

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 (45) hide show
  1. data/HISTORY.txt +4 -0
  2. data/Manifest.txt +25 -12
  3. data/README.txt +0 -2
  4. data/bin/rubysync +20 -6
  5. data/bin/rubysync.rb +333 -0
  6. data/docs/in_pipeline.graffle +2690 -0
  7. data/docs/init_openldap.ldif +11 -0
  8. data/docs/out_pipeline.graffle +3274 -0
  9. data/docs/schema/99rubysync.ldif +27 -0
  10. data/docs/schema/rubysync.schema +16 -0
  11. data/docs/to_sync.txt +15 -0
  12. data/docs/walkthru.txt +186 -0
  13. data/lib/ruby_sync.rb +7 -29
  14. data/lib/ruby_sync/connectors/base_connector.rb +55 -86
  15. data/lib/ruby_sync/connectors/csv_file_connector.rb +16 -4
  16. data/lib/ruby_sync/connectors/ldap_associations.rb +126 -0
  17. data/lib/ruby_sync/connectors/ldap_changelog_connector.rb +127 -0
  18. data/lib/ruby_sync/connectors/ldap_connector.rb +29 -192
  19. data/lib/ruby_sync/connectors/memory_connector.rb +1 -1
  20. data/lib/ruby_sync/connectors/xml_connector.rb +105 -32
  21. data/lib/ruby_sync/event.rb +40 -12
  22. data/lib/ruby_sync/operation.rb +18 -2
  23. data/lib/ruby_sync/pipelines/base_pipeline.rb +44 -6
  24. data/lib/ruby_sync/util/utilities.rb +97 -4
  25. data/lib/rubysync.rb +1 -1
  26. data/rubysync.tmproj +279 -59
  27. data/test/.LCKts_rubysync.rb~ +1 -0
  28. data/test/ruby_sync_test.rb +9 -4
  29. data/test/{test_active_record_vault.rb → tc_active_record_connector.rb} +11 -7
  30. data/test/{test_base_connector.rb → tc_base_connector.rb} +1 -1
  31. data/test/{test_base_pipeline.rb → tc_base_pipeline.rb} +1 -1
  32. data/test/tc_changelog_ldap_connector.rb +93 -0
  33. data/test/{test_csv_file_connector.rb → tc_csv_file_connector.rb} +14 -5
  34. data/test/{test_event.rb → tc_event.rb} +1 -1
  35. data/test/{test_ldap_changelog.rb → tc_ldap_changelog.rb} +1 -1
  36. data/test/{test_ldap_connector.rb → tc_ldap_connector.rb} +20 -22
  37. data/test/{test_ldap_vault.rb → tc_ldap_vault.rb} +2 -2
  38. data/test/{test_ldif.rb → tc_ldif.rb} +1 -1
  39. data/test/{test_memory_connectors.rb → tc_memory_connectors.rb} +10 -6
  40. data/test/{test_rubysync.rb → tc_rubysync.rb} +4 -4
  41. data/test/tc_transformation.rb +71 -0
  42. data/test/{test_utilities.rb → tc_utilities.rb} +28 -1
  43. data/test/tc_xml_connectors.rb +107 -6
  44. data/test/ts_rubysync.rb +11 -6
  45. metadata +33 -28
@@ -17,17 +17,25 @@ module RubySync
17
17
  class CsvFileConnector < RubySync::Connectors::FileConnector
18
18
 
19
19
  option :field_names, # A list of names representing the namesspace for this connector
20
- :path_field # The name of the field to use as the source_path
20
+ :path_field, # The name of the field to use as the source_path
21
+ :header_line # true if the first line is a header and should be ignored during imports
21
22
 
22
23
  in_glob '*.csv'
23
24
  out_extension '.csv'
24
25
  field_names []
25
- path_field (get_field_names.empty?)? 'field_0': @field_names[0]
26
+ path_field((get_field_names.empty?)? 'field_0': @field_names[0])
27
+
26
28
 
27
29
  # Called for each filename matching in_glob in in_path
28
30
  # Yields a modify event for each row found in the file.
29
31
  def each_file_change(filename)
32
+ header = header_line
30
33
  CSV.open(filename, 'r') do |row|
34
+ if header # should we ignore the first line
35
+ header = false
36
+ next
37
+ end
38
+
31
39
  if defined? field_name &&row.length > field_names.length
32
40
  log.warn "#{name}: Row in file #{filename} exceeds defined field_names"
33
41
  end
@@ -35,7 +43,7 @@ module RubySync
35
43
  data = {}
36
44
  row.each_index do |i|
37
45
  field_name = (i < field_names.length)? field_names[i] : "field_#{i}"
38
- data[field_name] = row[i].data
46
+ row[i] and data[field_name] = row[i].data
39
47
  end
40
48
  association_key = source_path = path_for(data)
41
49
  yield RubySync::Event.modify(self, source_path, association_key, create_operations_for(data))
@@ -44,7 +52,11 @@ module RubySync
44
52
 
45
53
  def self.sample_config
46
54
  return <<END
47
-
55
+
56
+ # True if the first line of each file is a header
57
+ # and should be ignored
58
+ header_line true
59
+
48
60
  field_names ['names', 'of', 'the', 'columns']
49
61
  path_field 'name_of_field_to_use_as_the_id'
50
62
  in_path '/directory/to/read/files/from'
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2007 Ritchie Young. All rights reserved.
4
+ #
5
+ # This file is part of RubySync.
6
+ #
7
+ # RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
9
+ #
10
+ # RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
11
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
14
+ # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15
+
16
+
17
+ lib_path = File.dirname(__FILE__) + '/..'
18
+ $:.unshift lib_path unless $:.include?(lib_path) || $:.include?(File.expand_path(lib_path))
19
+
20
+ require 'ruby_sync'
21
+ require 'ldap_connector'
22
+ $VERBOSE = false
23
+ require 'net/ldap'
24
+ $VERBOSE = true
25
+
26
+
27
+ RUBYSYNC_ASSOCIATION_ATTRIBUTE = "RubySyncAssociation"
28
+ RUBYSYNC_ASSOCIATION_CLASS = "RubySyncSynchable"
29
+
30
+
31
+ module LdapAssociations
32
+
33
+
34
+ def associate association, path
35
+ with_ldap do |ldap|
36
+ # todo: check and warn if path is outside of search_base
37
+ ldap.modify :dn=>path, :operations=>[
38
+ [:add, RUBYSYNC_ASSOCIATION_ATTRIBUTE, association.to_s]
39
+ ]
40
+ end
41
+ end
42
+
43
+ def path_for_association association
44
+ with_ldap do |ldap|
45
+ filter = "#{RUBYSYNC_ASSOCIATION_ATTRIBUTE}=#{association.to_s}"
46
+ log.debug "Searching with filter: #{filter}"
47
+ results = ldap.search :base=>@search_base,
48
+ :filter=>filter,
49
+ :attributes=>[]
50
+ results or return nil
51
+ case results.length
52
+ when 0: return nil
53
+ when 1: return results[0].dn
54
+ else
55
+ raise Exception.new("Duplicate association found for #{association.to_s}")
56
+ end
57
+ end
58
+ end
59
+
60
+ def associations_for path
61
+ with_ldap do |ldap|
62
+ results = ldap.search :base=>path,
63
+ :scope=>Net::LDAP::SearchScope_BaseObject,
64
+ :attributes=>[RUBYSYNC_ASSOCIATION_ATTRIBUTE]
65
+ unless results and results.length > 0
66
+ log.warn "Attempted association lookup on non-existent LDAP entry '#{path}'"
67
+ return []
68
+ end
69
+ associations = results[0][RUBYSYNC_ASSOCIATION_ATTRIBUTE]
70
+ return (associations)? as_array(associations) : []
71
+ end
72
+ end
73
+
74
+ def remove_association association
75
+ path = path_for_association association
76
+ with_ldap do |ldap|
77
+ ldap.modify :dn=>path, :modifications=>[
78
+ [:delete, RUBYSYNC_ASSOCIATION_ATTRIBUTE, association.to_s]
79
+ ]
80
+ end
81
+ end
82
+
83
+
84
+ # def associate_with_foreign_key key, path
85
+ # with_ldap do |ldap|
86
+ # ldap.add_attribute(path, association_attribute, key.to_s)
87
+ # end
88
+ # end
89
+ #
90
+ # def path_for_foreign_key key
91
+ # entry = entry_for_foreign_key key
92
+ # (entry)? entry.dn : nil
93
+ # end
94
+ #
95
+ # def foreign_key_for path
96
+ # entry = self[path]
97
+ # (entry)? entry.dn : nil # TODO: That doesn't look right. Should return an association key, not a path.
98
+ # end
99
+ #
100
+ # def remove_foreign_key key
101
+ # with_ldap do |ldap|
102
+ # entry = entry_for_foreign_key key
103
+ # if entry
104
+ # modify :dn=>entry.dn, :operations=>[ [:delete, association_attribute, key] ]
105
+ # end
106
+ # end
107
+ # end
108
+ #
109
+ # def find_associated foreign_key
110
+ # entry = entry_for_foreign_key key
111
+ # (entry)? operations_for_entry(entry) : nil
112
+ # end
113
+
114
+ private
115
+
116
+ def entry_for_foreign_key key
117
+ with_ldap do |ldap|
118
+ result = ldap.search :base=>search_base, :filter=>"#{association_attribute}=#{key}"
119
+ return nil if !result or result.size == 0
120
+ result[0]
121
+ end
122
+ end
123
+
124
+ end
125
+
126
+
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2007 Ritchie Young. All rights reserved.
4
+ #
5
+ # This file is part of RubySync.
6
+ #
7
+ # RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
9
+ #
10
+ # RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
11
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
14
+ # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15
+
16
+
17
+ lib_path = File.dirname(__FILE__) + '/..'
18
+ $:.unshift lib_path unless $:.include?(lib_path) || $:.include?(File.expand_path(lib_path))
19
+
20
+ require 'ruby_sync'
21
+ require 'ldap_connector'
22
+ require 'net/ldif'
23
+ $VERBOSE = false
24
+ require 'net/ldap'
25
+ #$VERBOSE = true
26
+
27
+ class LdapChangelogConnector < RubySync::Connectors::LdapConnector
28
+
29
+ option :changelog_dn
30
+ changelog_dn "cn=changelog"
31
+
32
+ def initialize options={}
33
+ super options
34
+ @last_change_number = 1
35
+ # TODO: Persist the current CSN, for now we'll just skip to the end of the changelog
36
+ skip_existing_changelog_entries
37
+ end
38
+ # Look for changelog entries. This is not supported by all LDAP servers
39
+ # Changelog entries have these attributes
40
+ # targetdn
41
+ # changenumber
42
+ # objectclass
43
+ # changes
44
+ # changetime
45
+ # changetype
46
+ # dn
47
+ #
48
+ # TODO: Detect presence/location of changelog from root DSE
49
+ def each_change
50
+ with_ldap do |ldap|
51
+ log.debug "@last_change_number = #{@last_change_number}"
52
+ filter = "(changenumber>=#{@last_change_number})"
53
+ first = true
54
+ @full_refresh_required = false
55
+ ldap.search :base => changelog_dn, :filter =>filter do |change|
56
+ change_number = change.changenumber[0].to_i
57
+ if first
58
+ first = false
59
+ # TODO: Persist the change_number so that we don't do a full resync everytime rubysync starts
60
+ if change_number != @last_change_number
61
+ log.warn "Earliest change number (#{change_number}) differs from that recorded (#{@last_change_number})."
62
+ log.warn "A full refresh is required."
63
+ @full_refresh_required = true
64
+ break
65
+ end
66
+ else
67
+ @last_change_number = change_number if change_number > @last_change_number
68
+ # todo: A proper DN object would be nice instead of string manipulation
69
+ target_dn = change.targetdn[0].gsub(/\s*,\s*/,',')
70
+ if target_dn =~ /#{search_base}$/oi
71
+ change_type = change.changetype[0]
72
+ event = event_for_changelog_entry(change)
73
+ yield event
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+
81
+ def skip_existing_changelog_entries
82
+ with_ldap do |ldap|
83
+ filter = "(changenumber>=#{@last_change_number})"
84
+ @full_refresh_required = false
85
+ ldap.search :base => changelog_dn, :filter =>filter do |change|
86
+ change_number = change.changenumber[0].to_i
87
+ @last_change_number = change_number if change_number > @last_change_number
88
+ end
89
+ end
90
+ end
91
+
92
+
93
+ # Called by unit tests to inject data
94
+ def test_add id, details
95
+ details << RubySync::Operation.new(:add, "objectclass", ['inetOrgPerson', 'organizationalPerson', 'person', 'top', 'RubySyncSynchable'])
96
+ add id, details
97
+ end
98
+
99
+
100
+ private
101
+
102
+
103
+ def event_for_changelog_entry cle
104
+ payload = nil
105
+ dn = cle.targetdn[0]
106
+ changetype = cle.changetype[0]
107
+ if cle.attribute_names.include? :changes
108
+ payload = []
109
+ cr = Net::LDIF.parse("dn: #{dn}\nchangetype: #{changetype}\n#{cle.changes[0]}")[0]
110
+ if changetype.to_sym == :add
111
+ # cr.data will be a hash of arrays or strings (attr-name=>[value1, value2, ...])
112
+ cr.data.each do |name, values|
113
+ payload << RubySync::Operation.add(name, values)
114
+ end
115
+ else
116
+ # cr.data will be an array of arrays of form [:action, :subject, [values]]
117
+ cr.data.each do |record|
118
+ payload << RubySync::Operation.new(record[0], record[1], record[2])
119
+ end
120
+ end
121
+ end
122
+ RubySync::Event.new(changetype, self, dn, nil, payload)
123
+ end
124
+
125
+ end
126
+
127
+
@@ -23,8 +23,6 @@ $VERBOSE = false
23
23
  require 'net/ldap'
24
24
  #$VERBOSE = true
25
25
 
26
- RUBYSYNC_ASSOCIATION_ATTRIBUTE = "RubySyncAssociation"
27
- RUBYSYNC_ASSOCIATION_CLASS = "RubySyncSynchable"
28
26
 
29
27
  class Net::LDAP::Entry
30
28
  def to_hash
@@ -36,27 +34,22 @@ module RubySync::Connectors
36
34
  class LdapConnector < RubySync::Connectors::BaseConnector
37
35
 
38
36
  option :host,
39
- :port,
40
- :bind_method,
41
- :username,
42
- :password,
43
- :search_filter,
44
- :search_base,
45
- :association_attribute, # name of the attribute in which to store the association key(s)
46
- :changelog_dn
37
+ :port,
38
+ :bind_method,
39
+ :username,
40
+ :password,
41
+ :search_filter,
42
+ :search_base,
43
+ :association_attribute # name of the attribute in which to store the association key(s)
47
44
 
48
45
  association_attribute 'RubySyncAssociation'
49
46
  bind_method :simple
50
47
  host 'localhost'
51
48
  port 389
52
49
  search_filter "cn=*"
53
- changelog_dn "cn=changelog"
54
50
 
55
51
  def initialize options={}
56
- super options
57
- @last_change_number = 1
58
- # TODO: Persist the current CSN, for now we'll just skip to the end of the changelog
59
- skip_existing_changelog_entries
52
+ super options
60
53
  end
61
54
 
62
55
 
@@ -64,68 +57,11 @@ module RubySync::Connectors
64
57
  #TODO: If vault, check the schema to make sure that the association_attribute is there
65
58
  end
66
59
 
67
-
68
- # Look for changelog entries. This is not supported by all LDAP servers
69
- # you may need to subclass for OpenLDAP and Active Directory
70
- # Changelog entries have these attributes
71
- # targetdn
72
- # changenumber
73
- # objectclass
74
- # changes
75
- # changetime
76
- # changetype
77
- # dn
78
- #
79
- # TODO: Detect presence/location of changelog from root DSE
80
- def each_change
81
- with_ldap do |ldap|
82
- log.debug "@last_change_number = #{@last_change_number}"
83
- filter = "(changenumber>=#{@last_change_number})"
84
- first = true
85
- @full_refresh_required = false
86
- ldap.search :base => changelog_dn, :filter =>filter do |change|
87
- change_number = change.changenumber[0].to_i
88
- if first
89
- first = false
90
- # TODO: Persist the change_number so that we don't do a full resync everytime rubysync starts
91
- if change_number != @last_change_number
92
- log.warn "Earliest change number (#{change_number}) differs from that recorded (#{@last_change_number})."
93
- log.warn "A full refresh is required."
94
- @full_refresh_required = true
95
- break
96
- end
97
- else
98
- @last_change_number = change_number if change_number > @last_change_number
99
- # todo: A proper DN object would be nice instead of string manipulation
100
- target_dn = change.targetdn[0].gsub(/\s*,\s*/,',')
101
- if target_dn =~ /#{search_base}$/oi
102
- change_type = change.changetype[0]
103
- event = event_for_changelog_entry(change)
104
- yield event
105
- end
106
- end
107
- end
108
- end
109
- end
110
-
111
-
112
- def skip_existing_changelog_entries
113
- with_ldap do |ldap|
114
- filter = "(changenumber>=#{@last_change_number})"
115
- @full_refresh_required = false
116
- ldap.search :base => changelog_dn, :filter =>filter do |change|
117
- change_number = change.changenumber[0].to_i
118
- @last_change_number = change_number if change_number > @last_change_number
119
- end
120
- end
121
- end
122
60
 
123
61
  def each_entry
124
62
  Net::LDAP.open(:host=>host, :port=>port, :auth=>auth) do |ldap|
125
- ldap.search :base => search_base, :filter => search_filter do |entry|
126
- operations = operations_for_entry(entry)
127
- association_key = (is_vault?)? nil : entry.dn
128
- yield RubySync::Event.add(self, entry.dn, association_key, operations)
63
+ ldap.search :base => search_base, :filter => search_filter do |ldap_entry|
64
+ yield ldap_entry.dn, to_entry(ldap_entry)
129
65
  end
130
66
  end
131
67
  end
@@ -137,10 +73,6 @@ module RubySync::Connectors
137
73
  log.warn "Returning a likely sample set."
138
74
  %w{ cn givenName sn }
139
75
  end
140
-
141
-
142
- def stopped
143
- end
144
76
 
145
77
 
146
78
 
@@ -148,11 +80,11 @@ module RubySync::Connectors
148
80
  return <<END
149
81
 
150
82
  host 'localhost'
151
- port 10389
152
- username 'uid=admin,ou=system'
83
+ port 389
84
+ username 'cn=Manager,dc=my-domain,dc=com'
153
85
  password 'secret'
154
86
  search_filter "cn=*"
155
- search_base "dc=example,dc=com"
87
+ search_base "ou=users,o=my-organization,dc=my-domain,dc=com"
156
88
  #:bind_method :simple
157
89
  END
158
90
  end
@@ -160,12 +92,16 @@ END
160
92
 
161
93
 
162
94
  def add(path, operations)
95
+ result = nil
163
96
  with_ldap do |ldap|
164
- ldap.add :dn=>path, :attributes=>perform_operations(operations)
97
+ attributes = perform_operations(operations)
98
+ result = ldap.add :dn=>path, :attributes=>attributes
165
99
  end
100
+ log.debug("ldap.add returned '#{result}'")
166
101
  return true
167
- rescue Net::LdapException
168
- log.warning "Exception occurred while adding LDAP record"
102
+ rescue Exception
103
+ log.warn "Exception occurred while adding LDAP record"
104
+ log.debug $!
169
105
  false
170
106
  end
171
107
 
@@ -192,7 +128,7 @@ END
192
128
 
193
129
  # Called by unit tests to inject data
194
130
  def test_add id, details
195
- details << RubySync::Operation.new(:add, "objectclass", ['inetOrgPerson', 'organizationalPerson', 'person', 'top', 'RubySyncSynchable'])
131
+ details << RubySync::Operation.new(:add, "objectclass", ['inetOrgPerson'])
196
132
  add id, details
197
133
  end
198
134
 
@@ -201,111 +137,17 @@ END
201
137
  #is_vault? and event.add_value 'objectclass', RUBYSYNC_ASSOCIATION_CLASS
202
138
  end
203
139
 
204
- def associate association, path
205
- with_ldap do |ldap|
206
- # todo: check and warn if path is outside of search_base
207
- ldap.modify :dn=>path, :operations=>[
208
- [:add, RUBYSYNC_ASSOCIATION_ATTRIBUTE, association.to_s]
209
- ]
210
- end
211
- end
212
-
213
- def path_for_association association
214
- with_ldap do |ldap|
215
- filter = "#{RUBYSYNC_ASSOCIATION_ATTRIBUTE}=#{association.to_s}"
216
- log.debug "Searching with filter: #{filter}"
217
- results = ldap.search :base=>@search_base,
218
- :filter=>filter,
219
- :attributes=>[]
220
- results or return nil
221
- case results.length
222
- when 0: return nil
223
- when 1: return results[0].dn
224
- else
225
- raise Exception.new("Duplicate association found for #{association.to_s}")
226
- end
227
- end
228
- end
229
-
230
- def associations_for path
231
- with_ldap do |ldap|
232
- results = ldap.search :base=>path,
233
- :scope=>Net::LDAP::SearchScope_BaseObject,
234
- :attributes=>[RUBYSYNC_ASSOCIATION_ATTRIBUTE]
235
- unless results and results.length > 0
236
- log.warn "Attempted association lookup on non-existent LDAP entry '#{path}'"
237
- return []
238
- end
239
- associations = results[0][RUBYSYNC_ASSOCIATION_ATTRIBUTE]
240
- return (associations)? associations.as_array : []
241
- end
242
- end
243
-
244
- def remove_association association
245
- path = path_for_association association
246
- with_ldap do |ldap|
247
- ldap.modify :dn=>path, :modifications=>[
248
- [:delete, RUBYSYNC_ASSOCIATION_ATTRIBUTE, association.to_s]
249
- ]
250
- end
251
- end
252
-
253
-
254
- # def associate_with_foreign_key key, path
255
- # with_ldap do |ldap|
256
- # ldap.add_attribute(path, association_attribute, key.to_s)
257
- # end
258
- # end
259
- #
260
- # def path_for_foreign_key key
261
- # entry = entry_for_foreign_key key
262
- # (entry)? entry.dn : nil
263
- # end
264
- #
265
- # def foreign_key_for path
266
- # entry = self[path]
267
- # (entry)? entry.dn : nil # TODO: That doesn't look right. Should return an association key, not a path.
268
- # end
269
- #
270
- # def remove_foreign_key key
271
- # with_ldap do |ldap|
272
- # entry = entry_for_foreign_key key
273
- # if entry
274
- # modify :dn=>entry.dn, :operations=>[ [:delete, association_attribute, key] ]
275
- # end
276
- # end
277
- # end
278
- #
279
- # def find_associated foreign_key
280
- # entry = entry_for_foreign_key key
281
- # (entry)? operations_for_entry(entry) : nil
282
- # end
283
140
 
284
141
 
285
- private
142
+ private
286
143
 
287
- def event_for_changelog_entry cle
288
- payload = nil
289
- dn = cle.targetdn[0]
290
- changetype = cle.changetype[0]
291
- if cle.attribute_names.include? :changes
292
- payload = []
293
- cr = Net::LDIF.parse("dn: #{dn}\nchangetype: #{changetype}\n#{cle.changes[0]}")[0]
294
- if changetype.to_sym == :add
295
- # cr.data will be a hash of arrays or strings (attr-name=>[value1, value2, ...])
296
- cr.data.each do |name, values|
297
- payload << RubySync::Operation.add(name, values)
298
- end
299
- else
300
- # cr.data will be an array of arrays of form [:action, :subject, [values]]
301
- cr.data.each do |record|
302
- payload << RubySync::Operation.new(record[0], record[1], record[2])
303
- end
304
- end
144
+ def to_entry ldap_entry
145
+ entry = {}
146
+ ldap_entry.each do |name, values|
147
+ entry[name.to_s] = values.map {|v| String.new(v)}
305
148
  end
306
- RubySync::Event.new(changetype, self, dn, nil, payload)
149
+ entry
307
150
  end
308
-
309
151
 
310
152
  def operations_for_entry entry
311
153
  ops = []
@@ -315,13 +157,8 @@ private
315
157
  ops
316
158
  end
317
159
 
318
- def entry_for_foreign_key key
319
- with_ldap do |ldap|
320
- result = ldap.search :base=>search_base, :filter=>"#{association_attribute}=#{key}"
321
- return nil if !result or result.size == 0
322
- result[0]
323
- end
324
- end
160
+
161
+
325
162
 
326
163
 
327
164
  def with_ldap