root/lib/ldap_shadows/object.rb @ cc630798
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/>.
|
|||
#++
|
|||
module LdapShadows
|
|||
class LdapObject < ActiveLdap::Base
|
|||
43bd8057 | Marc Dequènes (Duck) | class_inheritable_accessor :handle, :presentation, :mapper, :relations_info
|
|
89d8bebc | Marc Dequènes (Duck) | ||
ldap_mapping :prefix => '', :classes => ['top'], :scope => :sub
|
|||
e04ae9bc | Marc Dequènes (Duck) | # temporary method until active_ldap is fixed: return a DN object (see activeldap#23932)
|
|
89d8bebc | Marc Dequènes (Duck) | def dn_obj
|
|
ActiveLdap::DistinguishedName.parse(self.dn)
|
|||
end
|
|||
e04ae9bc | Marc Dequènes (Duck) | # temporary method until active_ldap is fixed: return a DN object (see activeldap#23932)
|
|
def self.base_obj
|
|||
ActiveLdap::DistinguishedName.parse(self.base)
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | def name
|
|
name = self[dn_attribute].is_a?(Array) ? self[dn_attribute][0] : self[dn_attribute]
|
|||
name.strip
|
|||
end
|
|||
5d28ad6e | Marc Dequènes (Duck) | def has_field?(field)
|
|
return false if field.downcase == "objectclass"
|
|||
has_attribute?(field)
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | def human_name
|
|
718238ae | Marc Dequènes (Duck) | attr_list = ['displayName', 'cn']
|
|
attr_list.unshift(self.class.presentation[:name_attribute]) if self.class.presentation.has_key?(:name_attribute)
|
|||
attr_list.each do |attr|
|
|||
if attr == 'dn'
|
|||
return self.dn
|
|||
elsif self.attribute_present?(attr)
|
|||
val = self.send(attr, true)
|
|||
return val[0].strip
|
|||
89d8bebc | Marc Dequènes (Duck) | end
|
|
end
|
|||
return ""
|
|||
end
|
|||
def description
|
|||
718238ae | Marc Dequènes (Duck) | attr_list = ['description']
|
|
attr_list.unshift(self.class.presentation[:desc_attribute]) if self.class.presentation.has_key?(:desc_attribute)
|
|||
attr_list.each do |attr|
|
|||
if self.attribute_present?(attr)
|
|||
89d8bebc | Marc Dequènes (Duck) | return self[attr].is_a?(Array) ? self[attr][0] : self[attr]
|
|
end
|
|||
end
|
|||
return ""
|
|||
end
|
|||
def possible_relations
|
|||
self.associations.collect {|assoc| assoc.to_s } - ['children']
|
|||
end
|
|||
def relations
|
|||
rel_list = []
|
|||
rel_list += self.class.presentation[:associated_relations] if self.class.presentation[:associated_relations]
|
|||
aspects.each do |aspect|
|
|||
aspect_data = self.class.mapper.get_aspect(aspect)
|
|||
if defined?(aspect_data[:presentation][:associated_relations]) and aspect_data[:presentation][:associated_relations]
|
|||
rel_list += aspect_data[:presentation][:associated_relations]
|
|||
end
|
|||
end
|
|||
rel_list & possible_relations
|
|||
end
|
|||
6089b33a | Marc Dequènes (Duck) | def self.possible_aspects
|
|
return [] unless self.presentation[:allowed_aspects]
|
|||
self.presentation[:allowed_aspects].collect{|key| key.to_s }.sort
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | def aspects
|
|
present_aspects = []
|
|||
(self.class.presentation[:allowed_aspects] || []).each do |aspect|
|
|||
aspect_data = self.class.mapper.get_aspect(aspect)
|
|||
aspect_mapping = aspect_data[:mapping]
|
|||
present_aspects << aspect if self.classes & aspect_mapping[:classes] == aspect_mapping[:classes]
|
|||
end
|
|||
present_aspects
|
|||
end
|
|||
a24bc5b1 | Marc Dequènes (Duck) | def self.objectclasses_attr_list(objectclass_list)
|
|
89d8bebc | Marc Dequènes (Duck) | objectclass_list = [objectclass_list] unless objectclass_list.is_a? Array
|
|
list = []
|
|||
objectclass_list.each do |objectclass|
|
|||
objectclass_obj = ActiveLdap::Base.schema.object_class(objectclass)
|
|||
attr_list = objectclass_obj.must + objectclass_obj.may
|
|||
list += attr_list.collect{|attr| attr.human_attribute_name }
|
|||
end
|
|||
list
|
|||
end
|
|||
a24bc5b1 | Marc Dequènes (Duck) | def self.possible_attributes
|
|
klasses = self.required_classes
|
|||
klasses += self.presentation[:optional_classes] if self.presentation.has_key?(:optional_classes)
|
|||
self.objectclasses_attr_list(klasses)
|
|||
end
|
|||
def self.possible_attributes_for_aspect(aspect)
|
|||
aspect_data = self.mapper.get_aspect(aspect)
|
|||
self.objectclasses_attr_list(aspect_data[:mapping][:classes])
|
|||
end
|
|||
43bd8057 | Marc Dequènes (Duck) | def info_for_relation(rel)
|
|
return nil unless self.relations.include?(rel)
|
|||
self.relations_info[rel.to_sym]
|
|||
end
|
|||
f7217dcd | Marc Dequènes (Duck) | def organized_data
|
|
1744c478 | Marc Dequènes (Duck) | ignored_attrs = self.mapper.get_global_config[:hidden_attributes] || []
|
|
ignored_attrs += self.class.presentation[:hidden_attributes] || []
|
|||
d9091cc0 | Marc Dequènes (Duck) | attr_list = self.nonempty_attributes - ignored_attrs
|
|
89d8bebc | Marc Dequènes (Duck) | ||
b52f0f7d | Marc Dequènes (Duck) | expert_attributes = (self.class.presentation[:expert_attributes] || [])
|
|
admin_attributes = attr_list.select do |attr|
|
|||
ActiveLdap::Base.schema.attribute(attr).operational?
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | aspects = self.aspects
|
|
rel_list = self.possible_relations
|
|||
# first pass to take aspects forced relations into account
|
|||
obj_aspects = {}
|
|||
aspects.each do |aspect|
|
|||
aspect_data = self.class.mapper.get_aspect(aspect)
|
|||
if defined?(aspect_data[:presentation][:associated_attributes]) and aspect_data[:presentation][:associated_attributes]
|
|||
taken_attr_list = aspect_data[:presentation][:associated_attributes] & (attr_list + ignored_attrs)
|
|||
unless taken_attr_list.empty?
|
|||
obj_aspects[aspect] ||= {}
|
|||
b52f0f7d | Marc Dequènes (Duck) | obj_aspects[aspect].merge!(fetch_attributes_data(taken_attr_list, expert_attributes, admin_attributes))
|
|
89d8bebc | Marc Dequènes (Duck) | attr_list -= taken_attr_list
|
|
end
|
|||
end
|
|||
if defined?(aspect_data[:presentation][:associated_relations]) and aspect_data[:presentation][:associated_relations]
|
|||
taken_rel_list = aspect_data[:presentation][:associated_relations] & rel_list
|
|||
unless taken_rel_list.empty?
|
|||
obj_aspects[aspect] ||= {}
|
|||
f7217dcd | Marc Dequènes (Duck) | obj_aspects[aspect].merge!(fetch_relations_data(taken_rel_list, expert_attributes))
|
|
89d8bebc | Marc Dequènes (Duck) | rel_list -= taken_rel_list
|
|
end
|
|||
end
|
|||
end
|
|||
# manage general attributes
|
|||
obj_info = {}
|
|||
if self.class.presentation[:associate_unclaimed_attributes]
|
|||
taken_attr_list = attr_list
|
|||
else
|
|||
b52f0f7d | Marc Dequènes (Duck) | taken_attr_list = admin_attributes
|
|
89d8bebc | Marc Dequènes (Duck) | if self.class.presentation.has_key?(:associated_attributes)
|
|
taken_attr_list += self.class.presentation[:associated_attributes]
|
|||
end
|
|||
a24bc5b1 | Marc Dequènes (Duck) | taken_attr_list += self.class.possible_attributes
|
|
89d8bebc | Marc Dequènes (Duck) | end
|
|
taken_attr_list = taken_attr_list.uniq & attr_list
|
|||
b52f0f7d | Marc Dequènes (Duck) | obj_info = fetch_attributes_data(taken_attr_list, expert_attributes, admin_attributes)
|
|
89d8bebc | Marc Dequènes (Duck) | attr_list -= taken_attr_list
|
|
# manage general relations
|
|||
if self.class.presentation[:associated_relations]
|
|||
taken_rel_list = self.class.presentation[:associated_relations] & rel_list
|
|||
unless taken_rel_list.empty?
|
|||
f7217dcd | Marc Dequènes (Duck) | obj_info.merge!(fetch_relations_data(taken_rel_list, expert_attributes))
|
|
89d8bebc | Marc Dequènes (Duck) | rel_list -= taken_rel_list
|
|
end
|
|||
end
|
|||
# second pass to dispath the remaining attributes
|
|||
unless attr_list.empty?
|
|||
aspects.each do |aspect|
|
|||
a24bc5b1 | Marc Dequènes (Duck) | taken_attr_list = (self.class.possible_attributes_for_aspect(aspect) & attr_list)
|
|
89d8bebc | Marc Dequènes (Duck) | obj_aspects[aspect] ||= {}
|
|
b52f0f7d | Marc Dequènes (Duck) | obj_aspects[aspect].merge!(fetch_attributes_data(taken_attr_list, expert_attributes, admin_attributes))
|
|
89d8bebc | Marc Dequènes (Duck) | attr_list -= taken_attr_list
|
|
break if attr_list.empty?
|
|||
end
|
|||
end
|
|||
[obj_info, obj_aspects]
|
|||
end
|
|||
3d5fa735 | Marc Dequènes (Duck) | def item_modify_from_string(str)
|
|
unless str =~ /^([a-zA-Z]*(?::[a-zA-Z]+)?)(=|\+=|-=)(.*)$/
|
|||
raise SyntaxError, _("modification parameter '%s' is invalid") % str
|
|||
end
|
|||
key = $1
|
|||
op = $2
|
|||
val = $3
|
|||
item_modify(key, op, val)
|
|||
end
|
|||
def item_modify(key, op, val)
|
|||
if key.index(":")
|
|||
type, field = key.split(":")
|
|||
else
|
|||
type = nil
|
|||
field = key
|
|||
end
|
|||
case type
|
|||
when nil
|
|||
item_modify_field(key, op, val)
|
|||
when 'rel'
|
|||
item_modify_relation(field, op, val)
|
|||
when ''
|
|||
case field
|
|||
when 'aspects'
|
|||
item_modify_aspects(op, val)
|
|||
else
|
|||
raise PreProcessingError, _("Unknown core field '%s'") % field
|
|||
end
|
|||
else
|
|||
raise PreProcessingError, _("Unknown type '%s' for field '%s'") % [type, field]
|
|||
end
|
|||
end
|
|||
def item_modify_field(field, op, val)
|
|||
unless self.has_field?(field)
|
|||
raise PreProcessingError, _("No such field '%s' in object '%s'") % [field, self.class.handle]
|
|||
end
|
|||
attr_info = ActiveLdap::Base.schema.attribute(field)
|
|||
if attr_info.read_only?
|
|||
raise PreProcessingError, _("The field '%s' cannot be modified (read only)") % field
|
|||
end
|
|||
if attr_info.binary?
|
|||
unless File.exists?(val)
|
|||
raise PreProcessingError, _("The field '%s' contains binary data, you must provide a filename instead of a direct value") % field
|
|||
end
|
|||
begin
|
|||
val = File.read(val)
|
|||
rescue
|
|||
raise PreProcessingError, _("The file for the binary field '%s' cannot be read: ") % [field, $!]
|
|||
end
|
|||
end
|
|||
old_val = self.send(field, true)
|
|||
# if val is nil or the latest value is removed, then the attribute is removed from the object,
|
|||
case op
|
|||
when '='
|
|||
return false if val == old_val
|
|||
val = [val] if old_val.is_a? Enumerable
|
|||
self.send(field + "=", val)
|
|||
when '+='
|
|||
if attr_info.single_value?
|
|||
raise PreProcessingError, _("The field '%s' cannot hold more than one value") % field
|
|||
end
|
|||
return false if old_val.include?(val)
|
|||
new_val = old_val << val
|
|||
self.send(field + "=", new_val)
|
|||
when '-='
|
|||
return false unless old_val.include?(val)
|
|||
new_val = old_val - [val]
|
|||
self.send(field + "=", new_val)
|
|||
else
|
|||
raise SyntaxError, _("Unknown operator '%s'") % op
|
|||
end
|
|||
true
|
|||
end
|
|||
def item_modify_relation(rel, op, val)
|
|||
unless self.relations.include?(rel)
|
|||
raise PreProcessingError, _("No such relation '%s' for object '%s'") % [rel, self.class.handle]
|
|||
end
|
|||
rel_info = self.info_for_relation(rel)
|
|||
if rel_info[:read_only]
|
|||
raise PreProcessingError, _("The relation '%s' cannot be modified (read only)") % rel
|
|||
end
|
|||
# fetch remote object in relation, which will be the real 'val'
|
|||
foreign_item_list = rel_info[:foreign_klass].find(:all, val)
|
|||
if foreign_item_list.empty?
|
|||
raise PreProcessingError, _("Foreign item '%s' for relation '%s' not found") % [val, rel]
|
|||
end
|
|||
if foreign_item_list.size > 1
|
|||
raise WeirdError, _("Ambiguous item '%s' for relation '%s' (%s possible items)") %
|
|||
[val, rel, foreign_item_list.size]
|
|||
end
|
|||
old_val = self.send(rel)
|
|||
val = foreign_item_list.first
|
|||
# if val is nil or the latest value is removed, then the association's attribute is removed from one side
|
|||
case op
|
|||
when '='
|
|||
val = [val] if old_val.is_a? Enumerable
|
|||
self.send(rel + "=", val)
|
|||
when '+='
|
|||
if rel_info[:single_value]
|
|||
raise PreProcessingError, _("The relation '%s' cannot hold more than one foreign item") % rel
|
|||
end
|
|||
return false if old_val.include?(val)
|
|||
self.send(rel) << val
|
|||
when '-='
|
|||
return false unless old_val.include?(val)
|
|||
self.send(rel).delete(val)
|
|||
else
|
|||
raise SyntaxError, _("Unknown operator '%s'") % op
|
|||
end
|
|||
true
|
|||
end
|
|||
def item_modify_aspects(op, aspect)
|
|||
unless self.class.possible_aspects.include?(aspect)
|
|||
raise PreProcessingError, _("No such aspect '%s' for object '%s'") % [aspect, self.class.handle]
|
|||
end
|
|||
case op
|
|||
when '='
|
|||
raise PreProcessingError, _("The equality operator is not possible for aspects")
|
|||
when '+='
|
|||
return false if self.aspects.include?(aspect)
|
|||
self.add_aspect(aspect)
|
|||
when '-='
|
|||
return false unless self.aspects.include?(aspect)
|
|||
self.remove_aspect(aspect)
|
|||
else
|
|||
raise SyntaxError, _("Unknown operator '%s'") % op
|
|||
end
|
|||
true
|
|||
end
|
|||
c30d4613 | Marc Dequènes (Duck) | def self.items_find_from_strings(str_list)
|
|
bd714351 | Marc Dequènes (Duck) | ldap_search_objects = "(objectClass=*)"
|
|
ldap_search_aspects = ""
|
|||
ldap_search_fields = []
|
|||
str_list.each do |str|
|
|||
unless str =~ /^([a-zA-Z]*(?::[a-zA-Z]+)?)(=|~=)(.*)$/
|
|||
raise SyntaxError, _("search parameter '%s' is invalid") % str
|
|||
end
|
|||
key = $1
|
|||
op = $2
|
|||
val = $3
|
|||
if key.index(":")
|
|||
type, field = key.split(":")
|
|||
else
|
|||
type = nil
|
|||
field = key
|
|||
end
|
|||
case type
|
|||
when nil
|
|||
ldap_search_fields << ldap_search_string_field(field, op, val)
|
|||
when 'rel'
|
|||
raise PreProcessingError, _("Searching relations is not implemented yet")
|
|||
when ''
|
|||
case field
|
|||
when 'objects'
|
|||
ldap_search_objects = ldap_search_string_objects(field, op, val)
|
|||
when 'aspects'
|
|||
ldap_search_aspects = ldap_search_string_aspects(field, op, val)
|
|||
else
|
|||
raise PreProcessingError, _("Unknown core field '%s'") % field
|
|||
end
|
|||
else
|
|||
raise PreProcessingError, _("Unknown type '%s' for field '%s'") % [type, field]
|
|||
end
|
|||
end
|
|||
ldap_search_string = "(&" + ldap_search_objects + ldap_search_aspects + ldap_search_fields.join + ")"
|
|||
c30d4613 | Marc Dequènes (Duck) | LdapObject.find(:all, :scope => :sub, :filter => ldap_search_string, :attributes => ["objectClass"])
|
|
bd714351 | Marc Dequènes (Duck) | end
|
|
def self.ldap_search_string_field(field, op, val)
|
|||
esc_val = self.connection.escape_filter_value(val)
|
|||
case op
|
|||
when "="
|
|||
"(#{field}=#{esc_val})"
|
|||
when "~="
|
|||
raise PreProcessingError, _("Searching with regex is not implemented yet")
|
|||
else
|
|||
raise SyntaxError, _("Unknown operator '%s'") % op
|
|||
end
|
|||
end
|
|||
def self.ldap_search_string_objects(field, op, val_list)
|
|||
ldap_search_parts = val_list.split(",").collect do |val|
|
|||
obj_hdl = val.downcase.singularize
|
|||
obj_klass = $ldapctl.find_klass(obj_hdl)
|
|||
raise PreProcessingError, _("No such object '%s'") % val if obj_klass.nil?
|
|||
ldap_classes = obj_klass.required_classes
|
|||
case op
|
|||
when "="
|
|||
"(&" + ldap_classes.collect{|cl| "(objectClass=#{cl})" }.join + ")"
|
|||
when "~="
|
|||
raise PreProcessingError, _("Searching with regex is not possible with objects")
|
|||
else
|
|||
raise SyntaxError, _("Unknown operator '%s'") % op
|
|||
end
|
|||
end
|
|||
"(|" + ldap_search_parts.join + ")"
|
|||
end
|
|||
def self.ldap_search_string_aspects(field, op, val_list)
|
|||
ldap_search_parts = val_list.split(",").collect do |val|
|
|||
aspect_data = self.mapper.get_aspect(val)
|
|||
raise PreProcessingError, _("No such aspect '%s'") % val if aspect_data.nil?
|
|||
ldap_classes = aspect_data[:mapping][:classes]
|
|||
case op
|
|||
when "="
|
|||
"(&" + ldap_classes.collect{|cl| "(objectClass=#{cl})" }.join + ")"
|
|||
when "~="
|
|||
raise PreProcessingError, _("Searching with regex is not possible with aspects")
|
|||
else
|
|||
raise SyntaxError, _("Unknown operator '%s'") % op
|
|||
end
|
|||
end
|
|||
"(&" + ldap_search_parts.join + ")"
|
|||
end
|
|||
a4aeb5ee | Marc Dequènes (Duck) | def self.find_raw_item_object(raw_item)
|
|
self.mapper.objects.each do |obj_hdl|
|
|||
obj_klass = $ldapctl.find_klass(obj_hdl)
|
|||
ldap_classes = obj_klass.required_classes
|
|||
c30d4613 | Marc Dequènes (Duck) | return obj_hdl if raw_item.classes & ldap_classes == ldap_classes
|
|
a4aeb5ee | Marc Dequènes (Duck) | end
|
|
nil
|
|||
end
|
|||
c30d4613 | Marc Dequènes (Duck) | def self.raw_item_info(raw_item)
|
|
obj_hdl = self.find_raw_item_object(raw_item)
|
|||
if obj_hdl
|
|||
obj_klass = $ldapctl.find_klass(obj_hdl)
|
|||
item = obj_klass.new(raw_item.dn)
|
|||
{:name => "#{obj_hdl}/#{item.name}", :item => item, :object => obj_klass}
|
|||
else
|
|||
{:name => "unknown/#{item_dn}"}
|
|||
end
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | def family_parent_dn
|
|
pdn = self.dn_obj.dup
|
|||
pdn.shift
|
|||
pdn
|
|||
end
|
|||
c30d4613 | Marc Dequènes (Duck) | def family_parent
|
|
# nothing found when using LdapObject, that's weird, so using ActiveLdap::Base
|
|||
# until further investigation
|
|||
#LdapObject.find(:first, :base => self.family_parent_dn.to_s, :scope => :base)
|
|||
ActiveLdap::Base.find(:first, :base => self.family_parent_dn.to_s, :scope => :base)
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | def family_children
|
|
LdapObject.find(:all, :base => self.dn, :scope => :one)
|
|||
end
|
|||
def family_children_dn
|
|||
self.family_children.collect {|obj| obj.dn }
|
|||
end
|
|||
def family_siblings
|
|||
# cannot substract, as the ruby object signature may be different
|
|||
LdapObject.find(:all, :base => self.family_parent_dn.to_s, :scope => :one).select{|obj| obj.dn != self.dn }
|
|||
end
|
|||
def family_siblings_dn
|
|||
self.family_siblings.collect {|obj| obj.dn }
|
|||
end
|
|||
0814bfc3 | Marc Dequènes (Duck) | def modified_attributes
|
|
list = []
|
|||
prepare_data_for_saving do |data, ldap_data|
|
|||
list = collect_modified_attributes(ldap_data, data)
|
|||
false
|
|||
end
|
|||
list
|
|||
end
|
|||
d9091cc0 | Marc Dequènes (Duck) | def add_aspect(aspect)
|
|
return unless self.class.possible_aspects.include?(aspect)
|
|||
aspect_data = self.mapper.get_aspect(aspect)
|
|||
add_class(*aspect_data[:mapping][:classes])
|
|||
13594999 | Marc Dequènes (Duck) | ||
# recursive dependency enforcement
|
|||
depends = aspect_data[:mapping][:depend_aspects] || []
|
|||
depends.each do |dep_aspect|
|
|||
add_aspect(dep_aspect)
|
|||
end
|
|||
d9091cc0 | Marc Dequènes (Duck) | end
|
|
def remove_aspect(aspect)
|
|||
return unless self.class.possible_aspects.include?(aspect)
|
|||
aspect_data = self.mapper.get_aspect(aspect)
|
|||
remove_class(*aspect_data[:mapping][:classes])
|
|||
end
|
|||
def nonempty_attributes
|
|||
self.attributes.collect{|key, val| (val.nil? or val == []) ? nil : key }.compact
|
|||
end
|
|||
def missing_attributes
|
|||
self.must.collect{|attr| attr.name } - self.nonempty_attributes - ['objectClass']
|
|||
end
|
|||
dba6a81b | Marc Dequènes (Duck) | def save
|
|
5aa80ef6 | Marc Dequènes (Duck) | before_save_jobs
|
|
dba6a81b | Marc Dequènes (Duck) | super
|
|
end
|
|||
def save!
|
|||
5aa80ef6 | Marc Dequènes (Duck) | before_save_jobs
|
|
dba6a81b | Marc Dequènes (Duck) | super
|
|
end
|
|||
89d8bebc | Marc Dequènes (Duck) | protected
|
|
5aa80ef6 | Marc Dequènes (Duck) | def before_save_jobs
|
|
check_hooks
|
|||
check_missing_attributes
|
|||
end
|
|||
dba6a81b | Marc Dequènes (Duck) | def check_hooks
|
|
self.aspects.each do |aspect|
|
|||
aklass = self.class.mapper.get_aspect_klass(aspect)
|
|||
next if aklass.nil?
|
|||
if self.new_entry?
|
|||
aklass.hook_create(self.class.mapper, self)
|
|||
else
|
|||
aklass.hook_mod(self.class.mapper, self)
|
|||
end
|
|||
end
|
|||
end
|
|||
5aa80ef6 | Marc Dequènes (Duck) | def check_missing_attributes
|
|
missing_fields = self.missing_attributes
|
|||
unless missing_fields.empty?
|
|||
miss_str = []
|
|||
missing_fields.each do |field|
|
|||
str = Translator.translate_field_name(field)
|
|||
str += " [#{field}]" if $program_options[:handles]
|
|||
miss_str << str
|
|||
end
|
|||
raise PreProcessingError, _("Cannot save the item; the following fields are missing: %s") %
|
|||
miss_str.join(", ")
|
|||
end
|
|||
end
|
|||
b52f0f7d | Marc Dequènes (Duck) | def fetch_attributes_data(attr_list, expert_attributes, admin_attributes)
|
|
f7217dcd | Marc Dequènes (Duck) | attr_data = self.attributes.collect do |key, val|
|
|
if attr_list.include?(key)
|
|||
[key, {
|
|||
:value => val,
|
|||
:multiple => (val.is_a?(Array) ? val.size : 1),
|
|||
:expert => expert_attributes.include?(key),
|
|||
b52f0f7d | Marc Dequènes (Duck) | :admin => admin_attributes.include?(key),
|
|
f7217dcd | Marc Dequènes (Duck) | :binary => ActiveLdap::Base.schema.attribute(key).binary?
|
|
}]
|
|||
else
|
|||
nil
|
|||
end
|
|||
end
|
|||
Hash[attr_data.compact]
|
|||
89d8bebc | Marc Dequènes (Duck) | end
|
|
f7217dcd | Marc Dequènes (Duck) | def fetch_relations_data(rel_list, expert_attributes)
|
|
89d8bebc | Marc Dequènes (Duck) | rel_data = rel_list.collect do |rel|
|
|
3d58e226 | Marc Dequènes (Duck) | data = self.send(rel)
|
|
if data.is_a? Enumerable
|
|||
if data.empty?
|
|||
value = nil
|
|||
else
|
|||
value = data.collect{|g| g.name }
|
|||
multiple = true
|
|||
end
|
|||
else
|
|||
a987d14b | Marc Dequènes (Duck) | # the exists? method also ensure the object is loaded
|
|
if data.exists?
|
|||
3d58e226 | Marc Dequènes (Duck) | value = data.name
|
|
9f623500 | Marc Dequènes (Duck) | else
|
|
value = nil
|
|||
3d58e226 | Marc Dequènes (Duck) | end
|
|
multiple = false
|
|||
end
|
|||
if value.nil?
|
|||
f7217dcd | Marc Dequènes (Duck) | nil
|
|
else
|
|||
3d58e226 | Marc Dequènes (Duck) | rel_key = "rel:" + rel
|
|
[rel_key, {
|
|||
:value => value,
|
|||
:multiple => multiple,
|
|||
:expert => expert_attributes.include?(rel_key),
|
|||
b52f0f7d | Marc Dequènes (Duck) | :admin => false,
|
|
f7217dcd | Marc Dequènes (Duck) | :binary => false
|
|
}]
|
|||
end
|
|||
89d8bebc | Marc Dequènes (Duck) | end
|
|
Hash[rel_data.compact]
|
|||
end
|
|||
end
|
|||
end
|