commit f706cc1dcc9263550db2ca8219d705c9015ee535
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Fri Oct 16 12:36:21 2009 +0200

    [evol] fix and improve before hooks for aspects

diff --git a/TODO b/TODO
index 40ab4f5..706680e 100644
--- a/TODO
+++ b/TODO
@@ -6,7 +6,10 @@
   a 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 family relationship ?
+- after-create/modify and before/after-delete hooks for aspects
+- whole hooks panoply for objects
 - handle language subtypes ? (would need the RFC2798 preferredLanguage
   parser out of the CyborgHood project)
 - support X-ORDERED attributetypes ?
-- search by family relationship ?
+
diff --git a/bin/shadowwalker b/bin/shadowwalker
index 74d0ac6..467302a 100755
--- a/bin/shadowwalker
+++ b/bin/shadowwalker
@@ -497,6 +497,9 @@ rescue ActiveLdap::OperationNotPermitted => e
 rescue ActiveLdap::Error => e
   STDERR.puts _("LDAP error: %s") % e.to_s
   exit 3
+rescue ProcessingError => e
+  STDERR.puts _("Processing error: %s") % e.to_s
+  exit 3
 rescue WeirdError =>e
   STDERR.puts _("Weird error: %s") % e.to_s
   exit 4
diff --git a/conf/ldap_shadows/shadows/MilkyPond/hooks/aspects/fs.rb b/conf/ldap_shadows/shadows/MilkyPond/hooks/aspects/fs.rb
index dc20e8e..df6a4be 100644
--- a/conf/ldap_shadows/shadows/MilkyPond/hooks/aspects/fs.rb
+++ b/conf/ldap_shadows/shadows/MilkyPond/hooks/aspects/fs.rb
@@ -5,14 +5,27 @@ MAX_UID = 65535
 STEP_UID = 100
 DEFAULT_GROUP = 'dc-users'
 
-def self.hook_modify(mapper, item)
+def self.hook_before_create(mapper, item)
+  hook_common(mapper, item)
+end
+
+def self.hook_before_modify(mapper, item)
+  hook_common(mapper, item)
+end
+
+def self.hook_common(mapper, item)
   unless item.attribute_present?('gidNumber')
     item.primaryGroup = mapper.find_klass(:group).find(:first, DEFAULT_GROUP)
   end
 
-  unless item.attribute_present?('uidNumber')
-    groups = ActiveLdap::Base.search(:scope => :sub, :filter => "(uidNumber=*)", :attributes => ['uidNumber'])
-    uidnumbers =  groups.collect {|group| group[1]['uidNumber'].first.to_i }
+  if item.attribute_present?('uidNumber')
+    user = ActiveLdap::Base.find(:first, :scope => :sub, :filter => "(&(objectClass=posixAccount)(uidNumber=#{item.uidNumber}))", :attributes => ['uidNumber'])
+    unless user.nil? or user.dn == item.dn
+      raise_error "UID already used by another item"
+    end
+  else
+    users = ActiveLdap::Base.find(:all, :scope => :sub, :filter => "(&(objectClass=posixAccount)(uidNumber=*))", :attributes => ['uidNumber'])
+    uidnumbers =  users.collect {|user| user.uidNumber }
 
     avail_uidnumber = nil
     min_uidn = MIN_UID
@@ -28,8 +41,7 @@ def self.hook_modify(mapper, item)
     end
 
     if avail_uidnumber.nil?
-      STDERR.puts "Available UID range is depleted."
-      exit 4
+      raise_error "Available UID range is depleted."
     else
       item.uidNumber = avail_uidnumber
     end
diff --git a/lib/ldap_shadows/controller.rb b/lib/ldap_shadows/controller.rb
index f37e975..403748c 100755
--- a/lib/ldap_shadows/controller.rb
+++ b/lib/ldap_shadows/controller.rb
@@ -109,7 +109,8 @@ module LdapShadows
       aspect_def.recursive_symbolize_keys!
       @aspects[aspect_name] = aspect_def
 
-      filename = File.join(Config::CFG_DIR, "hooks", "aspects", aspect_name.to_s.downcase + ".rb")
+      return if @shadow_config_path.nil?
+      filename = File.join(@shadow_config_path, "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)
@@ -354,10 +355,16 @@ module LdapShadows
   end
 
   class Aspect
-    def hook_create
+    def self.hook_before_create
     end
 
-    def hook_modify
+    def self.hook_before_modify
+    end
+
+    protected
+
+    def self.raise_error(msg)
+      raise ProcessingError, msg
     end
   end
 
diff --git a/lib/ldap_shadows/object.rb b/lib/ldap_shadows/object.rb
index 0f31a89..1aa0df5 100755
--- a/lib/ldap_shadows/object.rb
+++ b/lib/ldap_shadows/object.rb
@@ -570,19 +570,19 @@ module LdapShadows
     protected
 
     def before_save_jobs
-      check_hooks
+      check_hooks_before
       check_missing_attributes
     end
 
-    def check_hooks
+    def check_hooks_before
       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)
+          aklass.hook_before_create(self.class.mapper, self)
         else
-          aklass.hook_modify(self.class.mapper, self)
+          aklass.hook_before_modify(self.class.mapper, self)
         end
       end
     end
