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

#attributes, #canonical, canonical, combine_filters, create, create!, #delete, #delete!, #dn, entity_name, find_by_dn, hydrate, #initialize, make_search_filter, #modify, #modify_operations, #net_ldap, net_ldap, #new_record?, object_classes, required_attributes, schema_attribute, schema_attributes_array, schema_attributes_hash, search, set_schema_attributes, #setter_method?, #tainted_attributes, 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



196
197
198
199
# File 'lib/ucb_ldap_org.rb', line 196

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.



350
351
352
353
# File 'lib/ucb_ldap_org.rb', line 350

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.



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

def all_nodes
  @all_nodes ||= load_all_nodes
end

.all_nodes_iObject

Direct access to instance variables for unit testing



357
358
359
# File 'lib/ucb_ldap_org.rb', line 357

def all_nodes_i
  @all_nodes
end

.bind_for_whole_treeObject

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



302
303
304
305
306
# File 'lib/ucb_ldap_org.rb', line 302

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.



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

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.



325
326
327
328
# File 'lib/ucb_ldap_org.rb', line 325

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.



331
332
333
334
335
336
337
338
339
# File 'lib/ucb_ldap_org.rb', line 331

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



361
362
363
# File 'lib/ucb_ldap_org.rb', line 361

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.



255
256
257
# File 'lib/ucb_ldap_org.rb', line 255

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.



309
310
311
312
313
# File 'lib/ucb_ldap_org.rb', line 309

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


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

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 then 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.



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/ucb_ldap_org.rb', line 277

def load_all_nodes
  return @all_nodes if @all_nodes
  return nodes_from_test_cache if $TESTING && @test_node_cache
  
  @all_nodes = {}
  bind_for_whole_tree
  search(:filter => 'ou=*', :base => @tree_base).each do |org|
    @all_nodes[org.deptid] = org unless org.deptid == "Org Units"
  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.



317
318
319
320
321
322
# File 'lib/ucb_ldap_org.rb', line 317

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

.root_nodeObject

Returns the root node in the Org Tree.



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

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.



144
145
146
# File 'lib/ucb_ldap_org.rb', line 144

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

#child_nodes_iObject

Access to instance variables for testing



240
241
242
# File 'lib/ucb_ldap_org.rb', line 240

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



203
204
205
206
207
208
# File 'lib/ucb_ldap_org.rb', line 203

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.



149
150
151
# File 'lib/ucb_ldap_org.rb', line 149

def deptid
  ou.first
end

#init_child_nodesObject


Must be public for load_all_nodes()



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

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

#levelObject

Returns the entry’s level in the Org Tree.



155
156
157
# File 'lib/ucb_ldap_org.rb', line 155

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.



234
235
236
# File 'lib/ucb_ldap_org.rb', line 234

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

#nameObject

Returns the department name.



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

def name
  description.first
end

#parent_deptidObject

Returns parent node’s deptid



165
166
167
# File 'lib/ucb_ldap_org.rb', line 165

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.



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

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.



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

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.



191
192
193
# File 'lib/ucb_ldap_org.rb', line 191

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

#personsObject

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



212
213
214
# File 'lib/ucb_ldap_org.rb', line 212

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

#processing_unit?Boolean

Returns true if org is a processing unit.

Returns:

  • (Boolean)


180
181
182
# File 'lib/ucb_ldap_org.rb', line 180

def processing_unit?
  berkeleyEduOrgUnitProcessUnitFlag
end

#push_child_node(child_node) ⇒ Object


Add node to child node array.



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

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