Revision 3d5fa735
Added by Marc Dequènes over 15 years ago
- ID 3d5fa735b39fa6cb07d52a7f1cae6152ca45188d
TODO | ||
---|---|---|
- select parent at creation wirh :parent ? this could be integrated in
|
||
common code to be able to relocate an item
|
||
- find a way to restrict parent locations for new objects (regex for <obj>/<item> string ? regex for DN ? OR/AND with both ? ???)
|
||
- search by combination of objects/aspects/fields values
|
||
- aspect dependency support
|
bin/shadowwalker | ||
---|---|---|
|
||
modification_done = false
|
||
args.each do |mod_info|
|
||
unless mod_info =~ /^([a-zA-Z]*(?::[a-zA-Z]+)?)(=|\+=|-=)(.*)$/
|
||
raise SyntaxError, _("modification parameter '%s' is invalid") % mod_info
|
||
end
|
||
key = $1
|
||
op = $2
|
||
val = $3
|
||
|
||
if key.index(":")
|
||
type, field = key.split(":")
|
||
else
|
||
type = nil
|
||
field = key
|
||
end
|
||
|
||
case type
|
||
when nil
|
||
unless item.has_field?(field)
|
||
raise PreProcessingError, _("No such field '%s' in object '%s'") % [field, obj_klass.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 = item.send(field, true)
|
||
when 'rel'
|
||
unless item.relations.include?(field)
|
||
raise PreProcessingError, _("No such relation '%s' for object '%s'") % [field, obj_klass.handle]
|
||
end
|
||
|
||
rel_info = item.info_for_relation(field)
|
||
if rel_info[:read_only]
|
||
raise PreProcessingError, _("The relation '%s' cannot be modified (read only)") % field
|
||
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, field]
|
||
end
|
||
if foreign_item_list.size > 1
|
||
raise WeirdError, _("Ambiguous item '%s' for relation '%s' (%s possible items)") %
|
||
[val, field, foreign_item_list.size]
|
||
end
|
||
old_val = item.send(field)
|
||
val = foreign_item_list.first
|
||
when ''
|
||
case field
|
||
when 'aspects'
|
||
unless item.class.possible_aspects.include?(val)
|
||
raise PreProcessingError, _("No such aspect '%s' for object '%s'") % [val, obj_klass.handle]
|
||
end
|
||
else
|
||
raise PreProcessingError, _("Unknown core field '%s'") % field
|
||
end
|
||
else
|
||
raise PreProcessingError, _("Unknown type '%s' for field '%s'") % [type, field]
|
||
end
|
||
|
||
# if val is nil or the latest value is removed, then the atribute is removed from the object,
|
||
# or the association's attribute is removed from one side
|
||
case op
|
||
when '='
|
||
if type == '' and field == 'aspects'
|
||
raise PreProcessingError, _("The equality operator is not possible for aspects")
|
||
end
|
||
val = [val] if old_val.is_a? Enumerable
|
||
item.send(field + "=", val)
|
||
when '+='
|
||
case type
|
||
when nil
|
||
if attr_info.single_value?
|
||
raise PreProcessingError, _("The field '%s' cannot hold more than one value") % field
|
||
end
|
||
unless old_val.include?(val)
|
||
new_val = old_val << val
|
||
item.send(field + "=", new_val)
|
||
end
|
||
when 'rel'
|
||
if rel_info[:single_value]
|
||
raise PreProcessingError, _("The relation '%s' cannot hold more than one foreign item") % field
|
||
end
|
||
|
||
unless old_val.include?(val)
|
||
item.send(field) << val
|
||
end
|
||
when ''
|
||
case field
|
||
when 'aspects'
|
||
item.add_aspect(val)
|
||
end
|
||
end
|
||
when '-='
|
||
case type
|
||
when nil
|
||
new_val = old_val - [val]
|
||
item.send(field + "=", new_val)
|
||
when 'rel'
|
||
item.send(field).delete(val)
|
||
when ''
|
||
case field
|
||
when 'aspects'
|
||
item.remove_aspect(val)
|
||
end
|
||
end
|
||
end
|
||
modification_done = true
|
||
mod_done = item.item_modify_from_string(mod_info)
|
||
modification_done ||= mod_done
|
||
end
|
||
|
||
if modification_done
|
||
... | ... | |
item = obj_klass.new(item_hdl)
|
||
item.base = loc_item.dn_obj - obj_klass.base_obj
|
||
|
||
args.each do |param|
|
||
raise SyntaxError, _("creation parameter '%s' is invalid") % param unless param =~ /^([a-zA-Z]+)=(.*)$/
|
||
key = $1
|
||
val = $2
|
||
|
||
val = nil if val == ''
|
||
|
||
field = key
|
||
|
||
unless item.has_field?(field)
|
||
raise PreProcessingError, _("No such field '%s' in object '%s'") % [field, obj_klass.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: %s") % [field, $!]
|
||
end
|
||
end
|
||
|
||
item.send(field + "=", val)
|
||
modification_done = false
|
||
args.each do |mod_info|
|
||
mod_done = item.item_modify_from_string(mod_info)
|
||
modification_done ||= mod_done
|
||
end
|
||
|
||
item.save!
|
||
puts "Creation done."
|
||
end
|
||
end
|
||
cmdparser.add_command(CreateCommand.new)
|
lib/ldap_shadows/object.rb | ||
---|---|---|
[obj_info, obj_aspects]
|
||
end
|
||
|
||
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
|
||
|
||
def family_parent_dn
|
||
pdn = self.dn_obj.dup
|
||
pdn.shift
|
Also available in: Unified diff
[evol] move all item modification into LdapObject, clean things a bit, and use this code for creation too instead of the partial modification support needed to add the MUST attributetypes, this is more flexible