root/lib/ldap_shadows/controller.rb @ 10c5f7df
89d8bebc | Marc Dequènes (Duck) | #--
|
|
# LdapShadows, a Medium-level LDAP Access Library and Tool.
|
|||
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
|
|||
#
|
|||
# This program is free software: you can redistribute it and/or modify
|
|||
# it under the terms of the GNU General Public License as published by
|
|||
# the Free Software Foundation, either version 3 of the License, or
|
|||
# (at your option) any later version.
|
|||
#
|
|||
# This program is distributed in the hope that it will be useful,
|
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
# GNU General Public License for more details.
|
|||
#
|
|||
# You should have received a copy of the GNU General Public License
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#++
|
|||
$KCODE = 'UTF8'
|
|||
require 'jcode'
|
|||
require 'active_ldap'
|
|||
b52f0f7d | Marc Dequènes (Duck) | require 'ldap_shadows/activeldap_fixes'
|
|
89d8bebc | Marc Dequènes (Duck) | require 'ldap_shadows/object'
|
|
module LdapShadows
|
|||
class Controller
|
|||
0df6346a | Marc Dequènes (Duck) | attr_reader :shadow_name, :shadow_config_path
|
|
89d8bebc | Marc Dequènes (Duck) | def initialize(mod_container = LdapShadows::Objects)
|
|
@mod_container = mod_container
|
|||
74f1db3a | Marc Dequènes (Duck) | ||
clear_shadow
|
|||
LdapShadows::LdapObject.mapper = self
|
|||
end
|
|||
def clear_shadow
|
|||
0df6346a | Marc Dequènes (Duck) | @shadow_name = nil
|
|
@shadow_config_path = nil
|
|||
@global_config = nil
|
|||
@shadow_config = nil
|
|||
89d8bebc | Marc Dequènes (Duck) | @object_definitions = {}
|
|
@aspects = {}
|
|||
74f1db3a | Marc Dequènes (Duck) | # TODO: should replace @aspects properly one day
|
|
dba6a81b | Marc Dequènes (Duck) | @aspects2 = {}
|
|
89d8bebc | Marc Dequènes (Duck) | end
|
|
0df6346a | Marc Dequènes (Duck) | def set_shadow_config(shadow_config)
|
|
@shadow_config = shadow_config
|
|||
1744c478 | Marc Dequènes (Duck) | end
|
|
0df6346a | Marc Dequènes (Duck) | def get_shadow_config
|
|
@shadow_config
|
|||
1744c478 | Marc Dequènes (Duck) | end
|
|
89d8bebc | Marc Dequènes (Duck) | def set_aspect(aspect_name, aspect_def)
|
|
@aspects[aspect_name] = aspect_def
|
|||
dba6a81b | Marc Dequènes (Duck) | ||
filename = File.join(Config::CFG_DIR, "hooks", "aspects", aspect_name.to_s.downcase + ".rb")
|
|||
if File.exists?(filename)
|
|||
klass_name = "LdapAspect" + aspect_name.to_s.capitalize
|
|||
klass_content = IO.read(filename)
|
|||
begin
|
|||
Aspects.module_eval(<<-EOS)
|
|||
class #{klass_name} < Aspect
|
|||
#{klass_content}
|
|||
end
|
|||
EOS
|
|||
rescue
|
|||
0df6346a | Marc Dequènes (Duck) | raise PreProcessingError, _("Could not load Aspect plugin '%s'") % aspect_name
|
|
dba6a81b | Marc Dequènes (Duck) | end
|
|
@aspects2[aspect_name] = Aspects.const_get(klass_name)
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | end
|
|
def get_aspect(aspect_name)
|
|||
@aspects[aspect_name.to_sym]
|
|||
end
|
|||
dba6a81b | Marc Dequènes (Duck) | def get_aspect_klass(aspect_name)
|
|
@aspects2[aspect_name.to_sym]
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | def self.object_name_to_klass_name(obj_name)
|
|
"LdapObject" + obj_name.to_s.capitalize
|
|||
end
|
|||
def load_object(obj_name, obj_def)
|
|||
obj_mapping = obj_def[:mapping]
|
|||
klass_name = self.class.object_name_to_klass_name(obj_name)
|
|||
# create class
|
|||
@mod_container.module_eval(<<-EOS)
|
|||
class #{klass_name} < LdapShadows::LdapObject; end
|
|||
EOS
|
|||
# configure class
|
|||
klass = find_klass(obj_name)
|
|||
bbb82941 | Marc Dequènes (Duck) | klass.handle = obj_name
|
|
89d8bebc | Marc Dequènes (Duck) | klass.presentation = obj_def[:presentation]
|
|
klass.mapper = self
|
|||
klass.ldap_mapping obj_mapping.reject {|key, val| not ActiveLdap::Base::VALID_LDAP_MAPPING_OPTIONS.include?(key) }
|
|||
# store definition for later relations processing
|
|||
@object_definitions[obj_name] = obj_def
|
|||
end
|
|||
def find_klass(obj_name)
|
|||
klass_name = self.class.object_name_to_klass_name(obj_name)
|
|||
return nil unless @mod_container.const_defined?(klass_name)
|
|||
@mod_container.const_get(klass_name)
|
|||
end
|
|||
# run it _once_ when all objects are loaded
|
|||
def load_relations
|
|||
@object_definitions.each_pair do |obj_name, obj_def|
|
|||
obj_rel = {}
|
|||
obj_rel.merge!(obj_def[:relations]) if obj_def.include?(:relations)
|
|||
if obj_def[:presentation].has_key?(:allowed_aspects)
|
|||
b6fb956a | Marc Dequènes (Duck) | obj_def[:presentation][:allowed_aspects].each do |aspect|
|
|
aspect_data = get_aspect(aspect)
|
|||
if aspect_data.nil?
|
|||
0df6346a | Marc Dequènes (Duck) | raise PreProcessingError, _("Aspect '%s' is missing") % aspect
|
|
cee99c3d | Marc Dequènes (Duck) | end
|
|
b6fb956a | Marc Dequènes (Duck) | obj_rel.merge!(aspect_data[:relations]) if aspect_data.has_key?(:relations) and aspect_data[:relations]
|
|
89d8bebc | Marc Dequènes (Duck) | end
|
|
end
|
|||
next if obj_rel.empty?
|
|||
klass = find_klass(obj_name)
|
|||
43bd8057 | Marc Dequènes (Duck) | obj_relations_info = {}
|
|
89d8bebc | Marc Dequènes (Duck) | obj_rel.each_pair do |field_name, rel|
|
|
foreign_klass = find_klass(rel[:object])
|
|||
1d23b8e8 | Marc Dequènes (Duck) | if foreign_klass.nil?
|
|
0df6346a | Marc Dequènes (Duck) | raise PreProcessingError, _("Relation '%s' for object '%s' is impossible: foreign object '%s' is missing") % [field_name, obj_name, rel[:object]]
|
|
1d23b8e8 | Marc Dequènes (Duck) | end
|
|
89d8bebc | Marc Dequènes (Duck) | rel[:class_name] = foreign_klass.to_s
|
|
case rel[:type]
|
|||
when :belongs_to
|
|||
klass.belongs_to field_name, rel.reject {|key, val| not ActiveLdap::Associations::ClassMethods::VALID_BELONGS_TO_OPTIONS.include?(key) }
|
|||
when :has_many
|
|||
klass.has_many field_name, rel.reject {|key, val| not ActiveLdap::Associations::ClassMethods::VALID_HAS_MANY_OPTIONS.include?(key) }
|
|||
else
|
|||
raise "bug in '#{obj_name}' object relations (wrong type)"
|
|||
end
|
|||
43bd8057 | Marc Dequènes (Duck) | ||
obj_relations_info[field_name] = {
|
|||
:foreign_klass => foreign_klass,
|
|||
34cb4054 | Marc Dequènes (Duck) | :single_value => ActiveLdap::Base.schema.attribute(rel[:foreign_key]).single_value?,
|
|
:read_only => rel[:read_only] || false
|
|||
43bd8057 | Marc Dequènes (Duck) | }
|
|
89d8bebc | Marc Dequènes (Duck) | end
|
|
43bd8057 | Marc Dequènes (Duck) | klass.relations_info = obj_relations_info
|
|
89d8bebc | Marc Dequènes (Duck) | end
|
|
end
|
|||
6089b33a | Marc Dequènes (Duck) | ||
def objects
|
|||
@object_definitions.keys.collect{|key| key.to_s }.sort
|
|||
end
|
|||
74f1db3a | Marc Dequènes (Duck) | ||
def load_shadow(shadow_name = nil)
|
|||
clear_shadow
|
|||
0df6346a | Marc Dequènes (Duck) | g_config_file = File.join(LdapShadows::Config::CFG_DIR, "global.conf")
|
|
unless File.exists? g_config_file
|
|||
raise PreProcessingError, _("Global LdapShadows config file is missing")
|
|||
end
|
|||
g_default_config = {}
|
|||
g_config = g_default_config.merge(YAML.load(IO.read(g_config_file)) || {})
|
|||
g_config.recursive_symbolize_keys!
|
|||
@global_config = g_config
|
|||
@shadow_name = shadow_name || @global_config[:default_shadow]
|
|||
if @shadow_name.nil?
|
|||
raise PreProcessingError, _("Could not determine which Shadow to travel through")
|
|||
end
|
|||
@shadow_config_path = File.join(LdapShadows::Config::CFG_DIR, "shadows", @shadow_name)
|
|||
unless File.exists? @shadow_config_path
|
|||
raise PreProcessingError, _("Configuration directory for Shadow '%s' is missing") % @shadow_name
|
|||
end
|
|||
74f1db3a | Marc Dequènes (Duck) | ||
0df6346a | Marc Dequènes (Duck) | config_file = File.join(@shadow_config_path, "shadow.conf")
|
|
unless File.exists? config_file
|
|||
raise PreProcessingError, _("General configuration file for Shadow '%s' is missing") % @shadow_name
|
|||
end
|
|||
config = YAML.load(IO.read(config_file))
|
|||
74f1db3a | Marc Dequènes (Duck) | config_str_prv_filelist = [
|
|
File.join(ENV['HOME'], ".shadowwalker"),
|
|||
0df6346a | Marc Dequènes (Duck) | File.join(@shadow_config_path, "shadow_private.conf")
|
|
74f1db3a | Marc Dequènes (Duck) | ]
|
|
config_str_prv_filelist.each do |file|
|
|||
if File.exists?(file)
|
|||
config_str_prv = IO.read(file)
|
|||
config.merge!(YAML.load(config_str_prv))
|
|||
break
|
|||
end
|
|||
end
|
|||
config.recursive_symbolize_keys!
|
|||
0df6346a | Marc Dequènes (Duck) | $ldapctl.set_shadow_config(config[:presentation])
|
|
74f1db3a | Marc Dequènes (Duck) | ||
load_config_components("aspects") do |c_name, c_config|
|
|||
$ldapctl.set_aspect(c_name, c_config)
|
|||
end
|
|||
ActiveLdap::Base.setup_connection(config[:ldap])
|
|||
load_config_components("objects") do |c_name, c_config|
|
|||
$ldapctl.load_object(c_name, c_config)
|
|||
end
|
|||
$ldapctl.load_relations
|
|||
0df6346a | Marc Dequènes (Duck) | ||
translation_path = File.join($ldapctl.shadow_config_path, "translations")
|
|||
if File.exists? translation_path
|
|||
# load interface translation
|
|||
I18n.load_path += Dir[File.join(translation_path, "**", "*.yml")]
|
|||
end
|
|||
rescue
|
|||
raise PreProcessingError, _("Could not load shadow configiguration: %s") % $!
|
|||
74f1db3a | Marc Dequènes (Duck) | end
|
|
protected
|
|||
def load_config_components(type)
|
|||
0df6346a | Marc Dequènes (Duck) | c_config_dir = File.join(@shadow_config_path, type)
|
|
74f1db3a | Marc Dequènes (Duck) | c_config_pattern = File.join(c_config_dir, "**", "*.conf")
|
|
Dir.glob(c_config_pattern).each do |f|
|
|||
next if f[0..0] == "."
|
|||
c_name = File.basename(f).sub(".conf", "").to_sym
|
|||
c_config = YAML.load(IO.read(f))
|
|||
c_config.recursive_symbolize_keys!
|
|||
yield(c_name, c_config)
|
|||
end
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | end
|
|
# default location for mapped objects
|
|||
module Objects
|
|||
end
|
|||
dba6a81b | Marc Dequènes (Duck) | ||
class Aspect
|
|||
def hook_create
|
|||
end
|
|||
def hook_mod
|
|||
end
|
|||
end
|
|||
module Aspects
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | end
|