Class: UCB::LDAP::Org

Inherits:
Entry
  • Object
show all
Defined in:
lib/ucb_ldap_org.rb

Overview

UCB::LDAP::Org

Class for accessing the Org Unit tree of the UCB LDAP directory.

You can search by specifying your own filter:

e = Org.search(:filter => 'ou=jkasd')

But most of the time you’ll use the find_by_ou() method:

e = Org.find_by_ou('jkasd')

Get attribute values as if the attribute names were instance methods. Values returned reflect the cardinality and type as specified in the LDAP schema.

e = Org.find_by_ou('jkasd')

e.ou                                 #=> ['JKASD']
e.description                        #=> ['Application Services']
e.berkeleyEduOrgUnitProcessUnitFlag  #=> true

Convenience methods are provided that have friendlier names and return scalars for attributes the schema says are mulit-valued, but in practice are single-valued:

e = Org.find_by_ou('jkasd')

e.deptid                      #=> 'JKASD'
e.name                        #=> 'Application Services'
e.processing_unit?            #=> true

Other methods encapsulate common processing:

e.level                       #=> 4
e.parent_node                 #=> #<UCB::LDAP::Org: ...>
e.parent_node.deptid          #=> 'VRIST'
e.child_nodes                 #=> [#<UCB::LDAP::Org: ..>, ...]

You can retrieve people in a department. This will be an Array of UCB::LDAP::Person.

asd = Org.find_by_ou('jkasd')

asd_staff = asd.persons       #=> [#<UCB::LDAP::Person: ...>, ...]

Getting a Node’s Level “n” Code or Name

There are methods that will return the org code and org name at a particular level. They are implemented by method_missing and so are not documented in the instance method section.

o = Org.find_by_ou('jkasd')

o.code          #=> 'JKASD'
o.level         #=> 4
o.level_4_code  #=> 'JKASD'
o.level_3_name  #=> 'Info Services & Technology'
o.level_2_code  #=> 'AVCIS'
o.level_5_code  #=> nil

Dealing With the Entire Org Tree

There are several class methods that simplify most operations involving the entire org tree.

Org.all_nodes()

Returns a Hash of all org nodes whose keys are deptids and whose values are corresponding Org instances.

# List all nodes alphabetically by department name

nodes_by_name = Org.all_nodes.values.sort_by{|n| n.name.upcase}
nodes_by_name.each do |n|
  puts "#{n.deptid} - #{n.name}"
end

Org.flattened_tree()

Returns an Array of all nodes in hierarchy order.

UCB::LDAP::Org.flattened_tree.each do |node|
  puts "#{node.level} #{node.deptid} - #{node.name}"
end

Produces:

1 UCBKL - UC Berkeley Campus
2 AVCIS - Information Sys & Technology
3 VRIST - Info Systems & Technology
4 JFAVC - Office of the CIO
5 JFADM - Assoc VC Off General Ops
4 JGMIP - Museum Informatics Project
4 JHSSC - Social Sci Computing Lab    
etc.

Org.root_node()

Returns the root node in the Org Tree.

By recursing down child_nodes you can access the entire org tree:

# display deptid, name and children recursively
def display_node(node)
  indent = "  " * (node.level - 1)
  puts "#{indent} #{node.deptid} - #{node.name}"
  node.child_nodes.each{|child| display_node(child)}
end

# start at root node
display_node(Org.root_node)

Caching of Search Results

Calls to any of the following class methods automatically cache the entire Org tree:

  • all_nodes()

  • flattened_tree()

  • root_node()

Subsequent calls to any of these methods return the results from cache and don’t require another LDAP query.

Subsequent calls to find_by_ou() are done against the local cache. Searches done via the #search() method do not use the local cache.

Force loading of the cache by calling load_all_nodes().

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Entry

#assigned_attributes, #attributes, canonical, #canonical, combine_filters, create, create!, #delete, #delete!, #dn, entity_name, find_by_dn, #initialize, make_search_filter, #modify, #modify_operations, #net_ldap, net_ldap, object_classes, required_attributes, required_schema_attributes, schema_attribute, schema_attributes_array, schema_attributes_hash, search, set_schema_attributes, #setter_method?, tree_base, tree_base=, unique_object_class, #update_attributes, #update_attributes!, #value_getter, #value_setter

Constructor Details

This class inherits a constructor from UCB::LDAP::Entry

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object

Support for method names like level_2_code, level_2_name



216
217
218
219
# File 'lib/ucb_ldap_org.rb', line 216

def method_missing(method, *args) #:nodoc:
  return code_or_name_at_level($1, $2) if method.to_s =~ /^level_([1-6])_(code|name)$/
  super
end

Class Method Details

.add_to_flattened_tree(node) ⇒ Object

Adds a node and its children to @flattened_tree.



412
413
414
415
# File 'lib/ucb_ldap_org.rb', line 412

def add_to_flattened_tree(node)
  @flattened_tree.push node
  node.child_nodes.each { |child| add_to_flattened_tree child }
end

.all_nodesObject

Returns a Hash of all org nodes whose keys are deptids and whose values are corresponding Org instances.



289
290
291
# File 'lib/ucb_ldap_org.rb', line 289

def all_nodes()
  @all_nodes ||= load_all_nodes
end

.all_nodes_iObject

Direct access to instance variables for unit testing



419
420
421
# File 'lib/ucb_ldap_org.rb', line 419

def all_nodes_i()
  @all_nodes
end

.bind_for_whole_treeObject

Use bind that allows for retreiving entire org tree in one search.



353
354
355
356
357
# File 'lib/ucb_ldap_org.rb', line 353

def bind_for_whole_tree()
  username = "uid=istaswa-ruby,ou=applications,dc=berkeley,dc=edu"
  password = "t00lBox12"
  UCB::LDAP.authenticate(username, password)
end

.build_flattened_treeObject

Builds flattened tree. See RDoc for flattened_tree() for details.



402
403
404
405
406
407
# File 'lib/ucb_ldap_org.rb', line 402

def build_flattened_tree()
  load_all_nodes
  @flattened_tree = []
  add_to_flattened_tree UCB::LDAP::Org.root_node
  @flattened_tree
end

.build_test_node_cacheObject

Build cache of all nodes. Only used during testing.



382
383
384
385
# File 'lib/ucb_ldap_org.rb', line 382

def build_test_node_cache()
  @test_node_cache = {}
  @all_nodes.each { |k, v| @test_node_cache[k] = v.clone }
end

.calculate_all_child_nodesObject

Will calculate child_nodes for every node.



390
391
392
393
394
395
396
397
# File 'lib/ucb_ldap_org.rb', line 390

def calculate_all_child_nodes()
  @all_nodes.values.each { |node| node.init_child_nodes }
  @all_nodes.values.each do |node|
    next if node.deptid == 'UCBKL' || node.deptid == "Org Units"
    parent_node = find_by_ou_from_cache(node.parent_deptids.last)
    parent_node.push_child_node(node)
  end
end

.clear_all_nodesObject



423
424
425
# File 'lib/ucb_ldap_org.rb', line 423

def clear_all_nodes()
  @all_nodes = nil
end

.find_by_ou(ou) ⇒ Object Also known as: org_by_ou

Returns an instance of Org for the matching ou.



296
297
298
# File 'lib/ucb_ldap_org.rb', line 296

def find_by_ou(ou)
  find_by_ou_from_cache(ou) || search(:filter => {:ou => ou}).first
end

.find_by_ou_from_cache(ou) ⇒ Object

Returns an instance of Org from the local if cache exists, else nil.



362
363
364
365
366
# File 'lib/ucb_ldap_org.rb', line 362

def find_by_ou_from_cache(ou) #:nodoc:
  return nil if ou.nil?
  return nil unless @all_nodes
  @all_nodes[ou.upcase]
end

.flattened_tree(options = {}) ⇒ Object

Returns an Array of all nodes in hierarchy order. If you call with :level option, only nodes down to that level are returned.

Org.flattened_tree               # returns all nodes
Org.flattened_tree(:level => 3)  # returns down to level 3


313
314
315
316
317
# File 'lib/ucb_ldap_org.rb', line 313

def flattened_tree(options={})
  @flattened_tree ||= build_flattened_tree
  return @flattened_tree unless options[:level]
  @flattened_tree.reject { |o| o.level > options[:level] }
end

.load_all_nodesObject

Loads all org nodes and stores them in Hash returned by all_nodes(). Subsequent calls to find_by_ou() will be from cache and not require a trip to the LDAP server.



324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
# File 'lib/ucb_ldap_org.rb', line 324

def load_all_nodes()
  return @all_nodes if @all_nodes
  return nodes_from_test_cache if $TESTING && @test_node_cache
  
  bind_for_whole_tree
  @all_nodes = search.inject({}) do |accum, org|            
    accum[org.deptid] = org if org.deptid != "Org Units"
    accum
  end
  
  build_test_node_cache if $TESTING
  calculate_all_child_nodes
  UCB::LDAP.clear_authentication
  @all_nodes
end

.nodes_from_test_cacheObject

Returns cached nodes if we are testing and have already fetched all the nodes.



372
373
374
375
376
377
# File 'lib/ucb_ldap_org.rb', line 372

def nodes_from_test_cache()
  @all_nodes = {}
  @test_node_cache.each { |k, v| @all_nodes[k] = v.clone }
  calculate_all_child_nodes
  @all_nodes
end

.rebuild_node_cacheObject

Rebuild the org tree using fresh data from ldap



280
281
282
283
# File 'lib/ucb_ldap_org.rb', line 280

def rebuild_node_cache
  clear_all_nodes
  load_all_nodes
end

.root_nodeObject

Returns the root node in the Org Tree.



343
344
345
346
# File 'lib/ucb_ldap_org.rb', line 343

def root_node()
  load_all_nodes
  find_by_ou('UCBKL')
end

Instance Method Details

#child_nodesObject

Returns Array of child nodes, each an instance of Org, sorted by department id.



146
147
148
# File 'lib/ucb_ldap_org.rb', line 146

def child_nodes()
  @sorted_child_nodes ||= load_child_nodes.sort_by { |node| node.deptid }
end

#child_nodes_iObject

Access to instance variables for testing



269
270
271
# File 'lib/ucb_ldap_org.rb', line 269

def child_nodes_i()
  @child_nodes
end

#code_or_name_at_level(level, code_or_name) ⇒ Object

Return the level “n” code or name. Returns nil if level > self.level. Called from method_messing().



225
226
227
228
229
230
# File 'lib/ucb_ldap_org.rb', line 225

def code_or_name_at_level(level, code_or_name) #:nodoc:
  return (code_or_name == 'code' ? code : name) if level.to_i == self.level
  element = level.to_i - 1
  return parent_deptids[element] if code_or_name == 'code'
  parent_nodes[element] && parent_nodes[element].name
end

#deptidObject Also known as: code

Returns the department id.



153
154
155
# File 'lib/ucb_ldap_org.rb', line 153

def deptid()
  ou.first
end

#init_child_nodesObject


Must be public for load_all_nodes()



243
244
245
# File 'lib/ucb_ldap_org.rb', line 243

def init_child_nodes() #:nodoc:
  @child_nodes = []
end

#levelObject

Returns the entry’s level in the Org Tree.



161
162
163
# File 'lib/ucb_ldap_org.rb', line 161

def level()
  @level ||= parent_deptids.size + 1
end

#load_child_nodesObject

Loads child nodes for individual node. If all_nodes_nodes() has been called, child nodes are all loaded/calculated.



262
263
264
# File 'lib/ucb_ldap_org.rb', line 262

def load_child_nodes
  @child_nodes ||= UCB::LDAP::Org.search(:scope => 1, :base => dn, :filter => {:ou => '*'})
end

#nameObject

Returns the department name.



168
169
170
# File 'lib/ucb_ldap_org.rb', line 168

def name()
  description.first
end

#parent_deptidObject

Returns parent node’s deptid



175
176
177
# File 'lib/ucb_ldap_org.rb', line 175

def parent_deptid()
  @parent_deptid ||= parent_deptids.last
end

#parent_deptidsObject

Returns Array of parent deptids.

Highest level is first element; immediate parent is last element.



184
185
186
187
188
189
# File 'lib/ucb_ldap_org.rb', line 184

def parent_deptids()
  return @parent_deptids if @parent_deptids
  hierarchy_array = berkeleyEduOrgUnitHierarchyString.split("-")
  hierarchy_array.pop  # last element is deptid ... toss it
  @parent_deptids = hierarchy_array
end

#parent_nodeObject

Return parent node which is an instance of Org.



201
202
203
204
# File 'lib/ucb_ldap_org.rb', line 201

def parent_node()
  return nil if parent_deptids.size == 0
  @parent_node ||= UCB::LDAP::Org.find_by_ou parent_deptid
end

#parent_nodesObject

Returns Array of parent nodes which are instances of Org.



209
210
211
# File 'lib/ucb_ldap_org.rb', line 209

def parent_nodes()
  @parent_nodes ||= parent_deptids.map { |deptid| UCB::LDAP::Org.find_by_ou(deptid) }
end

#personsObject Also known as: people

Returns Array of UCB::LDAP::Person instances for each person in the org node.



236
237
238
# File 'lib/ucb_ldap_org.rb', line 236

def persons()
  @persons ||= UCB::LDAP::Person.search(:filter => {:departmentnumber => ou})
end

#processing_unit?Boolean

Returns true if org is a processing unit.

Returns:

  • (Boolean)


194
195
196
# File 'lib/ucb_ldap_org.rb', line 194

def processing_unit?()
  berkeleyEduOrgUnitProcessUnitFlag
end

#push_child_node(child_node) ⇒ Object


Add node to child node array.



249
250
251
252
253
254
# File 'lib/ucb_ldap_org.rb', line 249

def push_child_node(child_node)#:nodoc:
  @child_nodes ||= []
  unless @child_nodes.find { |n| n.ou == child_node.ou }
    @child_nodes.push(child_node)
  end
end