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().

Constant Summary

Constants inherited from Entry

Entry::TESTING

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Entry

#assigned_attributes, #attributes, canonical, #canonical, combine_filters, create, create!, #dn, entity_name, filter_in, find_by_dn, #initialize, make_search_filter, net_ldap, #net_ldap, object_classes, required_attributes, required_schema_attributes, schema_attribute, schema_attributes_array, schema_attributes_hash, search, set_schema_attributes, tree_base, tree_base=, unique_object_class

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.



404
405
406
407
# File 'lib/ucb_ldap/org.rb', line 404

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.



291
292
293
# File 'lib/ucb_ldap/org.rb', line 291

def all_nodes
  @all_nodes ||= load_all_nodes
end

.all_nodes_iObject

Direct access to instance variables for unit testing



411
412
413
# File 'lib/ucb_ldap/org.rb', line 411

def all_nodes_i
  @all_nodes
end

.build_flattened_treeObject

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



394
395
396
397
398
399
# File 'lib/ucb_ldap/org.rb', line 394

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.



374
375
376
377
# File 'lib/ucb_ldap/org.rb', line 374

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.



382
383
384
385
386
387
388
389
# File 'lib/ucb_ldap/org.rb', line 382

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.downcase == "org units"
    parent_node = find_by_ou_from_cache(node.parent_deptids.last)
    parent_node.push_child_node(node)
  end
end

.clear_all_nodesObject



415
416
417
# File 'lib/ucb_ldap/org.rb', line 415

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.



298
299
300
# File 'lib/ucb_ldap/org.rb', line 298

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.



354
355
356
357
358
# File 'lib/ucb_ldap/org.rb', line 354

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


315
316
317
318
319
# File 'lib/ucb_ldap/org.rb', line 315

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.



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

def load_all_nodes
  return @all_nodes if @all_nodes
  return nodes_from_test_cache if $TESTING && @test_node_cache

  @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
  @all_nodes
end

.nodes_from_test_cacheObject

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



364
365
366
367
368
369
# File 'lib/ucb_ldap/org.rb', line 364

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



282
283
284
285
# File 'lib/ucb_ldap/org.rb', line 282

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.



145
146
147
# File 'lib/ucb_ldap/org.rb', line 145

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

#child_nodes_iObject

Access to instance variables for testing



271
272
273
# File 'lib/ucb_ldap/org.rb', line 271

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.



152
153
154
# File 'lib/ucb_ldap/org.rb', line 152

def deptid
  ou.first
end

#init_child_nodesObject


Must be public for load_all_nodes()



244
245
246
# File 'lib/ucb_ldap/org.rb', line 244

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.



264
265
266
# File 'lib/ucb_ldap/org.rb', line 264

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.first.to_s })
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.



250
251
252
253
254
255
# File 'lib/ucb_ldap/org.rb', line 250

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