ucb_ldap 2.0.0.pre1 → 2.0.0.pre3
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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/CHANGELOG +137 -135
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/{README → README.md} +82 -80
- data/Rakefile +38 -20
- data/lib/ucb_ldap.rb +238 -204
- data/lib/{ucb_ldap_address.rb → ucb_ldap/address.rb} +106 -106
- data/lib/{ucb_ldap_affiliation.rb → ucb_ldap/affiliation.rb} +16 -16
- data/lib/{ucb_ldap_entry.rb → ucb_ldap/entry.rb} +455 -448
- data/lib/{ucb_ldap_person_job_appointment.rb → ucb_ldap/job_appointment.rb} +77 -79
- data/lib/{ucb_ldap_namespace.rb → ucb_ldap/namespace.rb} +40 -50
- data/lib/{ucb_ldap_org.rb → ucb_ldap/org.rb} +427 -429
- data/lib/{ucb_ldap_person.rb → ucb_ldap/person.rb} +157 -148
- data/lib/{person → ucb_ldap/person}/affiliation_methods.rb +23 -22
- data/lib/ucb_ldap/person/common_attributes.rb +63 -0
- data/lib/{ucb_ldap_schema.rb → ucb_ldap/schema.rb} +28 -28
- data/lib/{ucb_ldap_schema_attribute.rb → ucb_ldap/schema_attribute.rb} +152 -153
- data/lib/{ucb_ldap_service.rb → ucb_ldap/service.rb} +17 -19
- data/lib/{ucb_ldap_student_term.rb → ucb_ldap/student_term.rb} +29 -31
- data/lib/ucb_ldap/version.rb +3 -0
- data/spec/rails_binds.yml +9 -0
- data/spec/spec_helper.rb +43 -0
- data/spec/ucb_ldap/address_spec.rb +54 -0
- data/spec/ucb_ldap/affiliation_spec.rb +85 -0
- data/spec/ucb_ldap/entry_spec.rb +241 -0
- data/spec/ucb_ldap/job_appointment_spec.rb +65 -0
- data/spec/ucb_ldap/namespace_spec.rb +72 -0
- data/spec/ucb_ldap/org_spec.rb +217 -0
- data/spec/ucb_ldap/person_spec.rb +225 -0
- data/spec/ucb_ldap/schema_attribute_spec.rb +122 -0
- data/spec/ucb_ldap/schema_spec.rb +104 -0
- data/spec/ucb_ldap/service_spec.rb +127 -0
- data/spec/ucb_ldap/student_term_spec.rb +121 -0
- data/spec/ucb_ldap_spec.rb +182 -0
- data/ucb_ldap.gemspec +20 -27
- metadata +113 -64
- data/Manifest +0 -23
- data/TODO +0 -2
- data/lib/person/adv_con_person.rb +0 -0
- data/lib/person/generic_attributes.rb +0 -68
- data/lib/ucb_ldap_exceptions.rb +0 -27
- data/version.yml +0 -1
@@ -1,79 +1,77 @@
|
|
1
|
-
|
2
|
-
module
|
3
|
-
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
1
|
+
module UCB
|
2
|
+
module LDAP
|
3
|
+
# = UCB::LDAP::JobAppointment
|
4
|
+
#
|
5
|
+
# This class models a person's job appointment instance in the UCB LDAP directory.
|
6
|
+
#
|
7
|
+
# appts = JobAppontment.find_by_uid("1234") #=> [#<UCB::LDAP::JobAppointment: ...>, ...]
|
8
|
+
#
|
9
|
+
# JobAppointments are usually loaded through a Person instance:
|
10
|
+
#
|
11
|
+
# p = Person.find_by_uid("1234") #=> #<UCB::LDAP::Person: ...>
|
12
|
+
# appts = p.job_appointments #=> [#<UCB::LDAP::JobAppointment: ...>, ...]
|
13
|
+
#
|
14
|
+
# == Note on Binds
|
15
|
+
#
|
16
|
+
# You must have a privileged bind and pass your credentials to UCB::LDAP.authenticate()
|
17
|
+
# before performing your JobAppointment search.
|
18
|
+
#
|
19
|
+
class JobAppointment < Entry
|
20
|
+
@entity_name = 'personJobAppointment'
|
21
|
+
|
22
|
+
def cto_code
|
23
|
+
berkeleyEduPersonJobApptCTOCode
|
24
|
+
end
|
25
|
+
|
26
|
+
def deptid
|
27
|
+
berkeleyEduPersonJobApptDepartment
|
28
|
+
end
|
29
|
+
|
30
|
+
def record_number
|
31
|
+
berkeleyEduPersonJobApptEmpRecNumber.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
def personnel_program_code
|
35
|
+
berkeleyEduPersonJobApptPersPgmCode
|
36
|
+
end
|
37
|
+
|
38
|
+
def primary?
|
39
|
+
berkeleyEduPersonJobApptPrimaryFlag
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns Employee Relation Code
|
43
|
+
def erc_code
|
44
|
+
berkeleyEduPersonJobApptRelationsCode
|
45
|
+
end
|
46
|
+
|
47
|
+
def represented?
|
48
|
+
berkeleyEduPersonJobApptRepresentation != 'U'
|
49
|
+
end
|
50
|
+
|
51
|
+
def title_code
|
52
|
+
berkeleyEduPersonJobApptTitleCode
|
53
|
+
end
|
54
|
+
|
55
|
+
def appointment_type
|
56
|
+
berkeleyEduPersonJobApptType
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns +true+ if appointment is Without Salary
|
60
|
+
def wos?
|
61
|
+
berkeleyEduPersonJobApptWOS
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
# Returns an Array of JobAppointment for <tt>uid</tt>, sorted by
|
66
|
+
# record_number().
|
67
|
+
# Returns an empty Array ([]) if nothing is found.
|
68
|
+
#
|
69
|
+
def self.find_by_uid(uid)
|
70
|
+
base = "uid=#{uid},ou=people,dc=berkeley,dc=edu"
|
71
|
+
filter = Net::LDAP::Filter.eq("objectclass", 'berkeleyEduPersonJobAppt')
|
72
|
+
search(:base => base, :filter => filter).sort_by { |appt| appt.record_number }
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,50 +1,40 @@
|
|
1
|
-
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
@
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
##
|
26
|
-
# Returns
|
27
|
-
#
|
28
|
-
def uid
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# Returns Namespace instance for _cn_.
|
42
|
-
#
|
43
|
-
def find_by_cn(cn)
|
44
|
-
search(:filter => "cn=#{cn}").first
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
1
|
+
module UCB
|
2
|
+
module LDAP
|
3
|
+
##
|
4
|
+
# Class for accessing the Namespace/Name part of LDAP.
|
5
|
+
#
|
6
|
+
class Namespace < Entry
|
7
|
+
@tree_base = 'ou=names,ou=namespace,dc=berkeley,dc=edu'
|
8
|
+
@entity_name = 'namespaceName'
|
9
|
+
|
10
|
+
def name
|
11
|
+
cn.first
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Returns +Array+ of services
|
16
|
+
#
|
17
|
+
def services
|
18
|
+
berkeleyEduServices
|
19
|
+
end
|
20
|
+
|
21
|
+
def uid
|
22
|
+
super.first
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Returns an +Array+ of Namespace for _uid_.
|
27
|
+
#
|
28
|
+
def self.find_by_uid(uid)
|
29
|
+
search(:filter => "uid=#{uid}")
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Returns Namespace instance for _cn_.
|
34
|
+
#
|
35
|
+
def self.find_by_cn(cn)
|
36
|
+
search(:filter => "cn=#{cn}").first
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,429 +1,427 @@
|
|
1
|
-
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# e.
|
24
|
-
# e.
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# e.
|
34
|
-
# e.
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# e.
|
40
|
-
# e.parent_node
|
41
|
-
# e.
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
# o.
|
61
|
-
# o.
|
62
|
-
# o.
|
63
|
-
# o.
|
64
|
-
# o.
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
# nodes_by_name
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# 4
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
#
|
119
|
-
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
125
|
-
# *
|
126
|
-
# *
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
#
|
131
|
-
#
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
137
|
-
|
138
|
-
|
139
|
-
@
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
#
|
144
|
-
#
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
#
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
alias :code :deptid
|
157
|
-
|
158
|
-
##
|
159
|
-
# Returns the entry's level in the Org Tree.
|
160
|
-
#
|
161
|
-
def level
|
162
|
-
@level ||= parent_deptids.size + 1
|
163
|
-
end
|
164
|
-
|
165
|
-
##
|
166
|
-
# Returns the department name.
|
167
|
-
#
|
168
|
-
def name
|
169
|
-
description.first
|
170
|
-
end
|
171
|
-
|
172
|
-
##
|
173
|
-
# Returns parent node's deptid
|
174
|
-
#
|
175
|
-
def parent_deptid
|
176
|
-
@parent_deptid ||= parent_deptids.last
|
177
|
-
end
|
178
|
-
|
179
|
-
##
|
180
|
-
# Returns Array of parent deptids.
|
181
|
-
#
|
182
|
-
# Highest level is first element; immediate parent is last element.
|
183
|
-
#
|
184
|
-
def parent_deptids
|
185
|
-
return @parent_deptids if @parent_deptids
|
186
|
-
hierarchy_array = berkeleyEduOrgUnitHierarchyString.split("-")
|
187
|
-
hierarchy_array.pop
|
188
|
-
@parent_deptids = hierarchy_array
|
189
|
-
end
|
190
|
-
|
191
|
-
##
|
192
|
-
# Returns +true+ if org is a processing unit.
|
193
|
-
#
|
194
|
-
def processing_unit?
|
195
|
-
berkeleyEduOrgUnitProcessUnitFlag
|
196
|
-
end
|
197
|
-
|
198
|
-
##
|
199
|
-
# Return parent node which is an instance of Org.
|
200
|
-
#
|
201
|
-
def parent_node
|
202
|
-
return nil if parent_deptids.size == 0
|
203
|
-
@parent_node ||= UCB::LDAP::Org.find_by_ou
|
204
|
-
end
|
205
|
-
|
206
|
-
##
|
207
|
-
# Returns <tt>Array</tt> of parent nodes which are instances of Org.
|
208
|
-
#
|
209
|
-
def parent_nodes
|
210
|
-
@parent_nodes ||= parent_deptids.map { |deptid| UCB::LDAP::Org.find_by_ou(deptid) }
|
211
|
-
end
|
212
|
-
|
213
|
-
##
|
214
|
-
# Support for method names like level_2_code, level_2_name
|
215
|
-
#
|
216
|
-
def method_missing(method, *args) #:nodoc:
|
217
|
-
return code_or_name_at_level($1, $2) if method.to_s =~ /^level_([1-6])_(code|name)$/
|
218
|
-
super
|
219
|
-
end
|
220
|
-
|
221
|
-
##
|
222
|
-
# Return the level "n" code or name. Returns nil if level > self.level.
|
223
|
-
# Called from method_messing().
|
224
|
-
#
|
225
|
-
def code_or_name_at_level(level, code_or_name) #:nodoc:
|
226
|
-
return (code_or_name == 'code' ? code : name) if level.to_i == self.level
|
227
|
-
element = level.to_i - 1
|
228
|
-
return parent_deptids[element] if code_or_name == 'code'
|
229
|
-
parent_nodes[element] && parent_nodes[element].name
|
230
|
-
end
|
231
|
-
|
232
|
-
##
|
233
|
-
# Returns <tt>Array</tt> of UCB::LDAP::Person instances for each person
|
234
|
-
# in the org node.
|
235
|
-
#
|
236
|
-
def persons
|
237
|
-
@persons ||= UCB::LDAP::Person.search(:filter => {:departmentnumber => ou})
|
238
|
-
end
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
#
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
#
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
#
|
309
|
-
#
|
310
|
-
#
|
311
|
-
#
|
312
|
-
#
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
@flattened_tree
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
#
|
323
|
-
#
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
@all_nodes
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
end
|
429
|
-
end
|
1
|
+
module UCB
|
2
|
+
module LDAP
|
3
|
+
##
|
4
|
+
# =UCB::LDAP::Org
|
5
|
+
#
|
6
|
+
# Class for accessing the Org Unit tree of the UCB LDAP directory.
|
7
|
+
#
|
8
|
+
# You can search by specifying your own filter:
|
9
|
+
#
|
10
|
+
# e = Org.search(:filter => 'ou=jkasd')
|
11
|
+
#
|
12
|
+
# But most of the time you'll use the find_by_ou() method:
|
13
|
+
#
|
14
|
+
# e = Org.find_by_ou('jkasd')
|
15
|
+
#
|
16
|
+
# Get attribute values as if the attribute names were instance methods.
|
17
|
+
# Values returned reflect the cardinality and type as specified in the
|
18
|
+
# LDAP schema.
|
19
|
+
#
|
20
|
+
# e = Org.find_by_ou('jkasd')
|
21
|
+
#
|
22
|
+
# e.ou #=> ['JKASD']
|
23
|
+
# e.description #=> ['Application Services']
|
24
|
+
# e.berkeleyEduOrgUnitProcessUnitFlag #=> true
|
25
|
+
#
|
26
|
+
# Convenience methods are provided that have friendlier names
|
27
|
+
# and return scalars for attributes the schema says are mulit-valued,
|
28
|
+
# but in practice are single-valued:
|
29
|
+
#
|
30
|
+
# e = Org.find_by_ou('jkasd')
|
31
|
+
#
|
32
|
+
# e.deptid #=> 'JKASD'
|
33
|
+
# e.name #=> 'Application Services'
|
34
|
+
# e.processing_unit? #=> true
|
35
|
+
#
|
36
|
+
# Other methods encapsulate common processing:
|
37
|
+
#
|
38
|
+
# e.level #=> 4
|
39
|
+
# e.parent_node #=> #<UCB::LDAP::Org: ...>
|
40
|
+
# e.parent_node.deptid #=> 'VRIST'
|
41
|
+
# e.child_nodes #=> [#<UCB::LDAP::Org: ..>, ...]
|
42
|
+
#
|
43
|
+
#
|
44
|
+
# You can retrieve people in a department. This will be
|
45
|
+
# an +Array+ of UCB::LDAP::Person.
|
46
|
+
#
|
47
|
+
# asd = Org.find_by_ou('jkasd')
|
48
|
+
#
|
49
|
+
# asd_staff = asd.persons #=> [#<UCB::LDAP::Person: ...>, ...]
|
50
|
+
#
|
51
|
+
# === Getting a Node's Level "n" Code or Name
|
52
|
+
#
|
53
|
+
# There are methods that will return the org code and org name
|
54
|
+
# at a particular level. They are implemented by method_missing
|
55
|
+
# and so are not documented in the instance method section.
|
56
|
+
#
|
57
|
+
# o = Org.find_by_ou('jkasd')
|
58
|
+
#
|
59
|
+
# o.code #=> 'JKASD'
|
60
|
+
# o.level #=> 4
|
61
|
+
# o.level_4_code #=> 'JKASD'
|
62
|
+
# o.level_3_name #=> 'Info Services & Technology'
|
63
|
+
# o.level_2_code #=> 'AVCIS'
|
64
|
+
# o.level_5_code #=> nil
|
65
|
+
#
|
66
|
+
# == Dealing With the Entire Org Tree
|
67
|
+
#
|
68
|
+
# There are several class methods that simplify most operations
|
69
|
+
# involving the entire org tree.
|
70
|
+
#
|
71
|
+
# === Org.all_nodes()
|
72
|
+
#
|
73
|
+
# Returns a +Hash+ of all org nodes whose keys are deptids
|
74
|
+
# and whose values are corresponding Org instances.
|
75
|
+
#
|
76
|
+
# # List all nodes alphabetically by department name
|
77
|
+
#
|
78
|
+
# nodes_by_name = Org.all_nodes.values.sort_by{|n| n.name.upcase}
|
79
|
+
# nodes_by_name.each do |n|
|
80
|
+
# puts "#{n.deptid} - #{n.name}"
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# === Org.flattened_tree()
|
84
|
+
#
|
85
|
+
# Returns an +Array+ of all nodes in hierarchy order.
|
86
|
+
#
|
87
|
+
# UCB::LDAP::Org.flattened_tree.each do |node|
|
88
|
+
# puts "#{node.level} #{node.deptid} - #{node.name}"
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# Produces:
|
92
|
+
#
|
93
|
+
# 1 UCBKL - UC Berkeley Campus
|
94
|
+
# 2 AVCIS - Information Sys & Technology
|
95
|
+
# 3 VRIST - Info Systems & Technology
|
96
|
+
# 4 JFAVC - Office of the CIO
|
97
|
+
# 5 JFADM - Assoc VC Off General Ops
|
98
|
+
# 4 JGMIP - Museum Informatics Project
|
99
|
+
# 4 JHSSC - Social Sci Computing Lab
|
100
|
+
# etc.
|
101
|
+
#
|
102
|
+
# === Org.root_node()
|
103
|
+
#
|
104
|
+
# Returns the root node in the Org Tree.
|
105
|
+
#
|
106
|
+
# By recursing down child_nodes you can access the entire
|
107
|
+
# org tree:
|
108
|
+
#
|
109
|
+
# # display deptid, name and children recursively
|
110
|
+
# def display_node(node)
|
111
|
+
# indent = " " * (node.level - 1)
|
112
|
+
# puts "#{indent} #{node.deptid} - #{node.name}"
|
113
|
+
# node.child_nodes.each{|child| display_node(child)}
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# # start at root node
|
117
|
+
# display_node(Org.root_node)
|
118
|
+
#
|
119
|
+
# == Caching of Search Results
|
120
|
+
#
|
121
|
+
# Calls to any of the following class methods automatically cache
|
122
|
+
# the entire Org tree:
|
123
|
+
#
|
124
|
+
# * all_nodes()
|
125
|
+
# * flattened_tree()
|
126
|
+
# * root_node()
|
127
|
+
#
|
128
|
+
# Subsequent calls to any of these methods return the results from
|
129
|
+
# cache and don't require another LDAP query.
|
130
|
+
#
|
131
|
+
# Subsequent calls to find_by_ou() are done
|
132
|
+
# against the local cache. Searches done via the #search()
|
133
|
+
# method do <em>not</em> use the local cache.
|
134
|
+
#
|
135
|
+
# Force loading of the cache by calling load_all_nodes().
|
136
|
+
#
|
137
|
+
class Org < Entry
|
138
|
+
@entity_name = "org"
|
139
|
+
@tree_base = 'ou=org units,dc=berkeley,dc=edu'
|
140
|
+
|
141
|
+
##
|
142
|
+
# Returns <tt>Array</tt> of child nodes, each an instance of Org,
|
143
|
+
# sorted by department id.
|
144
|
+
#
|
145
|
+
def child_nodes
|
146
|
+
@sorted_child_nodes ||= load_child_nodes.sort_by { |node| node.deptid }
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Returns the department id.
|
151
|
+
#
|
152
|
+
def deptid
|
153
|
+
ou.first
|
154
|
+
end
|
155
|
+
|
156
|
+
alias :code :deptid
|
157
|
+
|
158
|
+
##
|
159
|
+
# Returns the entry's level in the Org Tree.
|
160
|
+
#
|
161
|
+
def level
|
162
|
+
@level ||= parent_deptids.size + 1
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Returns the department name.
|
167
|
+
#
|
168
|
+
def name
|
169
|
+
description.first
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# Returns parent node's deptid
|
174
|
+
#
|
175
|
+
def parent_deptid
|
176
|
+
@parent_deptid ||= parent_deptids.last
|
177
|
+
end
|
178
|
+
|
179
|
+
##
|
180
|
+
# Returns Array of parent deptids.
|
181
|
+
#
|
182
|
+
# Highest level is first element; immediate parent is last element.
|
183
|
+
#
|
184
|
+
def parent_deptids
|
185
|
+
return @parent_deptids if @parent_deptids
|
186
|
+
hierarchy_array = berkeleyEduOrgUnitHierarchyString.split("-")
|
187
|
+
hierarchy_array.pop # last element is deptid ... toss it
|
188
|
+
@parent_deptids = hierarchy_array
|
189
|
+
end
|
190
|
+
|
191
|
+
##
|
192
|
+
# Returns +true+ if org is a processing unit.
|
193
|
+
#
|
194
|
+
def processing_unit?
|
195
|
+
berkeleyEduOrgUnitProcessUnitFlag
|
196
|
+
end
|
197
|
+
|
198
|
+
##
|
199
|
+
# Return parent node which is an instance of Org.
|
200
|
+
#
|
201
|
+
def parent_node
|
202
|
+
return nil if parent_deptids.size == 0
|
203
|
+
@parent_node ||= UCB::LDAP::Org.find_by_ou(parent_deptid)
|
204
|
+
end
|
205
|
+
|
206
|
+
##
|
207
|
+
# Returns <tt>Array</tt> of parent nodes which are instances of Org.
|
208
|
+
#
|
209
|
+
def parent_nodes
|
210
|
+
@parent_nodes ||= parent_deptids.map { |deptid| UCB::LDAP::Org.find_by_ou(deptid) }
|
211
|
+
end
|
212
|
+
|
213
|
+
##
|
214
|
+
# Support for method names like level_2_code, level_2_name
|
215
|
+
#
|
216
|
+
def method_missing(method, *args) #:nodoc:
|
217
|
+
return code_or_name_at_level($1, $2) if method.to_s =~ /^level_([1-6])_(code|name)$/
|
218
|
+
super
|
219
|
+
end
|
220
|
+
|
221
|
+
##
|
222
|
+
# Return the level "n" code or name. Returns nil if level > self.level.
|
223
|
+
# Called from method_messing().
|
224
|
+
#
|
225
|
+
def code_or_name_at_level(level, code_or_name) #:nodoc:
|
226
|
+
return (code_or_name == 'code' ? code : name) if level.to_i == self.level
|
227
|
+
element = level.to_i - 1
|
228
|
+
return parent_deptids[element] if code_or_name == 'code'
|
229
|
+
parent_nodes[element] && parent_nodes[element].name
|
230
|
+
end
|
231
|
+
|
232
|
+
##
|
233
|
+
# Returns <tt>Array</tt> of UCB::LDAP::Person instances for each person
|
234
|
+
# in the org node.
|
235
|
+
#
|
236
|
+
def persons
|
237
|
+
@persons ||= UCB::LDAP::Person.search(:filter => { :departmentnumber => ou.first.to_s })
|
238
|
+
end
|
239
|
+
|
240
|
+
alias :people :persons
|
241
|
+
|
242
|
+
#---
|
243
|
+
# Must be public for load_all_nodes()
|
244
|
+
def init_child_nodes #:nodoc:
|
245
|
+
@child_nodes = []
|
246
|
+
end
|
247
|
+
|
248
|
+
#---
|
249
|
+
# Add node to child node array.
|
250
|
+
def push_child_node(child_node) #:nodoc:
|
251
|
+
@child_nodes ||= []
|
252
|
+
unless @child_nodes.find { |n| n.ou == child_node.ou }
|
253
|
+
@child_nodes.push(child_node)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
## TODO: restore private
|
258
|
+
#private unless $TESTING
|
259
|
+
|
260
|
+
##
|
261
|
+
# Loads child nodes for individual node. If all_nodes_nodes()
|
262
|
+
# has been called, child nodes are all loaded/calculated.
|
263
|
+
#
|
264
|
+
def load_child_nodes
|
265
|
+
@child_nodes ||= UCB::LDAP::Org.search(:scope => 1, :base => dn, :filter => { :ou => '*' })
|
266
|
+
end
|
267
|
+
|
268
|
+
##
|
269
|
+
# Access to instance variables for testing
|
270
|
+
#
|
271
|
+
def child_nodes_i
|
272
|
+
@child_nodes
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
class << self
|
277
|
+
#public
|
278
|
+
|
279
|
+
##
|
280
|
+
# Rebuild the org tree using fresh data from ldap
|
281
|
+
#
|
282
|
+
def rebuild_node_cache
|
283
|
+
clear_all_nodes
|
284
|
+
load_all_nodes
|
285
|
+
end
|
286
|
+
|
287
|
+
##
|
288
|
+
# Returns a +Hash+ of all org nodes whose keys are deptids
|
289
|
+
# and whose values are corresponding Org instances.
|
290
|
+
#
|
291
|
+
def all_nodes
|
292
|
+
@all_nodes ||= load_all_nodes
|
293
|
+
end
|
294
|
+
|
295
|
+
##
|
296
|
+
# Returns an instance of Org for the matching _ou_.
|
297
|
+
#
|
298
|
+
def find_by_ou(ou)
|
299
|
+
find_by_ou_from_cache(ou) || search(:filter => { :ou => ou }).first
|
300
|
+
end
|
301
|
+
|
302
|
+
##
|
303
|
+
# for backwards compatibility -- should be deprecated
|
304
|
+
#
|
305
|
+
alias :org_by_ou :find_by_ou
|
306
|
+
|
307
|
+
##
|
308
|
+
# Returns an +Array+ of all nodes in hierarchy order. If you call
|
309
|
+
# with <tt>:level</tt> option, only nodes down to that level are
|
310
|
+
# returned.
|
311
|
+
#
|
312
|
+
# Org.flattened_tree # returns all nodes
|
313
|
+
# Org.flattened_tree(:level => 3) # returns down to level 3
|
314
|
+
#
|
315
|
+
def flattened_tree(options={})
|
316
|
+
@flattened_tree ||= build_flattened_tree
|
317
|
+
return @flattened_tree unless options[:level]
|
318
|
+
@flattened_tree.reject { |o| o.level > options[:level] }
|
319
|
+
end
|
320
|
+
|
321
|
+
##
|
322
|
+
# Loads all org nodes and stores them in Hash returned by all_nodes().
|
323
|
+
# Subsequent calls to find_by_ou() will be from cache and not
|
324
|
+
# require a trip to the LDAP server.
|
325
|
+
#
|
326
|
+
def load_all_nodes
|
327
|
+
return @all_nodes if @all_nodes
|
328
|
+
return nodes_from_test_cache if $TESTING && @test_node_cache
|
329
|
+
|
330
|
+
tree_username = "uid=istaswa-ruby,ou=applications,dc=berkeley,dc=edu"
|
331
|
+
tree_password = "t00lBox12"
|
332
|
+
|
333
|
+
UCB::LDAP.with_credentials(tree_username, tree_password) do
|
334
|
+
@all_nodes = search.inject({}) do |accum, org|
|
335
|
+
accum[org.deptid] = org if org.deptid != "Org Units"
|
336
|
+
accum
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
build_test_node_cache if $TESTING
|
341
|
+
calculate_all_child_nodes
|
342
|
+
@all_nodes
|
343
|
+
end
|
344
|
+
|
345
|
+
##
|
346
|
+
# Returns the root node in the Org Tree.
|
347
|
+
#
|
348
|
+
def root_node
|
349
|
+
load_all_nodes
|
350
|
+
find_by_ou('UCBKL')
|
351
|
+
end
|
352
|
+
|
353
|
+
## TODO restore private
|
354
|
+
#private unless $TESTING
|
355
|
+
|
356
|
+
##
|
357
|
+
# Returns an instance of Org from the local if cache exists, else +nil+.
|
358
|
+
#
|
359
|
+
def find_by_ou_from_cache(ou) #:nodoc:
|
360
|
+
return nil if ou.nil?
|
361
|
+
return nil unless @all_nodes
|
362
|
+
@all_nodes[ou.upcase]
|
363
|
+
end
|
364
|
+
|
365
|
+
##
|
366
|
+
# Returns cached nodes if we are testing and have already
|
367
|
+
# fetched all the nodes.
|
368
|
+
#
|
369
|
+
def nodes_from_test_cache
|
370
|
+
@all_nodes = {}
|
371
|
+
@test_node_cache.each { |k, v| @all_nodes[k] = v.clone }
|
372
|
+
calculate_all_child_nodes
|
373
|
+
@all_nodes
|
374
|
+
end
|
375
|
+
|
376
|
+
##
|
377
|
+
# Build cache of all nodes. Only used during testing.
|
378
|
+
#
|
379
|
+
def build_test_node_cache
|
380
|
+
@test_node_cache = {}
|
381
|
+
@all_nodes.each { |k, v| @test_node_cache[k] = v.clone }
|
382
|
+
end
|
383
|
+
|
384
|
+
##
|
385
|
+
# Will calculate child_nodes for every node.
|
386
|
+
#
|
387
|
+
def calculate_all_child_nodes
|
388
|
+
@all_nodes.values.each { |node| node.init_child_nodes }
|
389
|
+
@all_nodes.values.each do |node|
|
390
|
+
next if node.deptid == 'UCBKL' || node.deptid == "Org Units"
|
391
|
+
parent_node = find_by_ou_from_cache(node.parent_deptids.last)
|
392
|
+
parent_node.push_child_node(node)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
##
|
397
|
+
# Builds flattened tree. See RDoc for flattened_tree() for details.
|
398
|
+
#
|
399
|
+
def build_flattened_tree
|
400
|
+
load_all_nodes
|
401
|
+
@flattened_tree = []
|
402
|
+
add_to_flattened_tree(UCB::LDAP::Org.root_node)
|
403
|
+
@flattened_tree
|
404
|
+
end
|
405
|
+
|
406
|
+
##
|
407
|
+
# Adds a node and its children to @flattened_tree.
|
408
|
+
#
|
409
|
+
def add_to_flattened_tree(node)
|
410
|
+
@flattened_tree.push(node)
|
411
|
+
node.child_nodes.each { |child| add_to_flattened_tree(child) }
|
412
|
+
end
|
413
|
+
|
414
|
+
# Direct access to instance variables for unit testing
|
415
|
+
|
416
|
+
def all_nodes_i
|
417
|
+
@all_nodes
|
418
|
+
end
|
419
|
+
|
420
|
+
def clear_all_nodes
|
421
|
+
@all_nodes = nil
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|