Get Add and Edit Extension forms working with LDAP
authorBen Klang <ben@alkaloid.net>
Fri, 1 Jan 2010 02:22:29 +0000 (21:22 -0500)
committerBen Klang <ben@alkaloid.net>
Fri, 1 Jan 2010 02:22:29 +0000 (21:22 -0500)
shout/extensions.php
shout/lib/Driver.php
shout/lib/Driver/Ldap.php
shout/lib/Driver/Sql.php
shout/lib/Forms/ExtensionForm.php
shout/lib/Shout.php

index 27e4e95..da4a4d1 100644 (file)
@@ -13,10 +13,6 @@ require_once SHOUT_BASE . '/lib/Forms/ExtensionForm.php';
 //require_once SHOUT_BASE . '/lib/Shout.php';
 
 $action = Horde_Util::getFormData('action');
-$extension = Horde_Util::getFormData('extension');
-$extensions = $shout_extensions->getExtensions($context);
-
-$vars = Horde_Variables::getDefaultVariables();
 
 //$tabs = Shout::getTabs($context, $vars);
 
@@ -26,46 +22,37 @@ $section = 'extensions';
 $title = _("Extensions: ");
 
 switch ($action) {
-case 'save':
-    $title .= sprintf(_("Save Extension %s"), $extension);
-    $FormName = $vars->get('formname');
-
-    $Form = &Horde_Form::singleton($FormName, $vars);
+case 'add':
+case 'edit':
+    $vars = Horde_Variables::getDefaultVariables();
+    $Form = new ExtensionDetailsForm($vars);
 
     $FormValid = $Form->validate($vars, true);
 
     if ($Form->isSubmitted() && $FormValid) {
         // Form is Valid and Submitted
         try {
-            $Form->execute();
+            $Form->execute($context);
+            $notification->push(_("User information updated."),
+                                  'horde.success');
+            $action = 'list';
         } catch (Exception $e) {
             $notification->push($e);
         }
-        $notification->push(_("User information updated."),
-                                  'horde.success');
-        break;
-     } else {
-         $action = 'edit';
-         // Fall-through to the "edit" action
-     }
-
-case 'add':
-case 'edit':
-    if ($action == 'add') {
-        $title .= _("New Extension");
-        // Treat adds just like an empty edit
-        $action = 'edit';
     } else {
-        $title .= sprintf(_("Edit Extension %s"), $extension);
-
+        // Create a new add/edit form
+        $extension = Horde_Util::getFormData('extension');
+        $extensions = $shout_extensions->getExtensions($context);
+        $vars = new Horde_Variables($extensions[$extension]);
+        if ($action == 'edit') {
+            $vars->set('oldextension', $extension);
+        }
+        $vars->set('action', $action);
+        $Form = new ExtensionDetailsForm($vars);
+        $Form->open($RENDERER, $vars, Horde::applicationUrl('extensions.php'), 'post');
+        // Make sure we get the right template below.
+        $action = 'edit';
     }
-
-    $FormName = 'ExtensionDetailsForm';
-    $vars = new Horde_Variables($extensions[$extension]);
-    $Form = &Horde_Form::singleton($FormName, $vars);
-
-    $Form->open($RENDERER, $vars, Horde::applicationUrl('extensions.php'), 'post');
-
     break;
 
 case 'delete':
@@ -87,6 +74,9 @@ default:
     $title .= _("List Users");
 }
 
+// Fetch the (possibly updated) list of extensions
+$extensions = $shout_extensions->getExtensions($context);
+
 require SHOUT_TEMPLATES . '/common-header.inc';
 require SHOUT_TEMPLATES . '/menu.inc';
 
index acb9c41..b343bb7 100644 (file)
@@ -114,6 +114,25 @@ class Shout_Driver {
     }
 
     /**
+     * Save an extension to the LDAP tree
+     *
+     * @param string $context Context to which the user should be added
+     *
+     * @param string $extension Extension to be saved
+     *
+     * @param array $details Phone numbers, PIN, options, etc to be saved
+     *
+     * @return TRUE on success, PEAR::Error object on error
+     * @throws Shout_Exception
+     */
+    public function saveExtension($context, $extension, $details)
+    {
+        if (!Shout::checkRights("shout:contexts:$context:extensions", PERMS_EDIT, 1)) {
+            throw new Shout_Exception(_("Permission denied to save extensions in this context."));
+        }
+    }
+
+    /**
      * Attempts to return a concrete Shout_Driver instance based on
      * $driver.
      *
index ee0358f..b654759 100644 (file)
@@ -91,7 +91,7 @@ class Shout_Driver_Ldap extends Shout_Driver
 
         $attributes = array(
             'cn',
-            'mail',
+            'AstVoicemailEmail',
             'AstVoicemailMailbox',
             'AstVoicemailPassword',
             'AstVoicemailOptions',
@@ -138,7 +138,7 @@ class Shout_Driver_Ldap extends Shout_Driver
                 $res[$i]['cn'][0];
 
             $entries[$context][$extension]['email'] =
-                $res[$i]['mail'][0];
+                $res[$i]['astvoicemailemail'][0];
 
             $entries[$context][$extension]['pageremail'] =
                 $res[$i]['astvoicemailpager'][0];
@@ -492,162 +492,96 @@ class Shout_Driver_Ldap extends Shout_Driver
      * @param array $details Phone numbers, PIN, options, etc to be saved
      *
      * @return TRUE on success, PEAR::Error object on error
+     * @throws Shout_Exception
      */
     public function saveExtension($context, $extension, $details)
     {
-        $ldapKey = &$this->_ldapKey;
-        $appKey = &$this->_appKey;
-        # FIXME Access Control/Authorization
-        if (!Shout::checkRights("shout:contexts:$context:extensions", PERMS_EDIT, 1)) {
-            // FIXME: Allow users to edit themselves
-            //&& !($details[$appKey] == Auth::getAuth())) {
-            throw new Shout_Exception(_("Permission denied to save extensions in this context."));
-        }
-
-        $contexts = &$this->getContexts();
-//         $domain = $contexts[$context]['domain'];
-
-        # Check to ensure the extension is unique within this context
-        $filter = "(&(objectClass=AstVoicemailMailbox)(context=$context))";
-        $reqattrs = array('dn', $ldapKey);
-        $res = @ldap_search($this->_LDAP,
-            SHOUT_USERS_BRANCH . ',' . $this->_params['basedn'],
-            $filter, $reqattrs);
-        if (!$res) {
-            return PEAR::raiseError('Unable to check directory for duplicate extension: ' .
-                ldap_error($this->_LDAP));
-        }
-        if (($res['count'] > 1) ||
-            ($res['count'] != 0 &&
-            !in_array($res[0][$ldapKey], $details[$appKey]))) {
-            return PEAR::raiseError('Duplicate extension found.  Not saving changes.');
-        }
-
+        parent::saveExtension($context, $extension, $details);
+
+        // FIXME: Fix and uncomment the below
+//        // Check to ensure the extension is unique within this context
+//        $filter = "(&(objectClass=AstVoicemailMailbox)(context=$context))";
+//        $reqattrs = array('dn', $ldapKey);
+//        $res = @ldap_search($this->_LDAP, $this->_params['basedn'],
+//                            $filter, $reqattrs);
+//        if ($res === false) {
+//            $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP),
+//                                                  ldap_error($this->_LDAP));
+//            Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR);
+//            throw new Shout_Exception(_("Error while searching the directory.  Details have been logged for the administrator."));
+//        }
+//        if (($res['count'] != 1) ||
+//            ($res['count'] != 0 &&
+//            !in_array($res[0][$ldapKey], $details[$appKey]))) {
+//            throw new Shout_Exception(_("Duplicate extension found.  Not saving changes."));
+//        }
+        // FIXME: Quote these strings
+        $uid = $extension . '@' . $context;
         $entry = array(
+            'objectClass' => array('top', 'account', 'AsteriskVoicemail'),
+            'uid' => $uid,
             'cn' => $details['name'],
-            'sn' => $details['name'],
-            'mail' => $details['email'],
-            'uid' => $details['email'],
-            'voiceMailbox' => $details['newextension'],
-            'voiceMailboxPin' => $details['mailboxpin'],
-            'context' => $context,
-            'asteriskUserDialOptions' => $details['dialopts'],
+            'AstVoicemailEmail' => $details['email'],
+            'AstVoicemailMailbox' => $extension,
+            'AstVoicemailPassword' => $details['mailboxpin'],
+            'AstContext' => $context,
         );
-
-        if (!empty ($details['telephonenumber'])) {
-            $entry['telephoneNumber'] = $details['telephonenumber'];
-        }
-
-        $validusers = &$this->getUsers($context);
-        if (!isset($validusers[$extension])) {
-            # Test to see if we're modifying an existing user that has
-            # no telephone system objectClasses and update that object/user
-            $rdn = $ldapKey.'='.$details[$appKey].',';
-            $branch = SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
-
-            # This test is something of a hack.  I want a cheap way to check
-            # for the existance of an object.  I don't want to do a full search
-            # so instead I compare that the dn equals the dn.  If the object
-            # exists then it'll return true.  If the object doesn't exist,
-            # it'll return error.  If it ever returns false something wierd
-            # is going on.
-            $res = @ldap_compare($this->_LDAP, $rdn.$branch,
-                    $ldapKey, $details[$appKey]);
+        $rdn = 'uid=' . $uid;
+        $dn = $rdn . ',' . $this->_params['basedn'];
+
+        if (!empty($details['oldextension'])) {
+            // This is a change to an existing extension
+            // First, identify the DN to modify
+            // FIXME: Quote these strings
+            $filter = '(&(AstVoicemailMailbox=%s)(AstContext=%s))';
+            $filter = sprintf($filter, $details['oldextension'], $context);
+            $attributes = array('dn');
+
+            $res = ldap_search($this->_LDAP, $this->_params['basedn'],
+                               $filter, $attributes);
             if ($res === false) {
-                # We should never get here: a DN should ALWAYS match itself
-                return PEAR::raiseError("Internal Error: " . __FILE__ . " at " .
-                    __LINE__);
-            } elseif ($res === true) {
-                # The object/user exists but doesn't have the Asterisk
-                # objectClasses
-                $extension = $details['newextension'];
-
-                # $tmp is the minimal information required to establish
-                # an account in LDAP as required by the objectClasses.
-                # The entry will be fully populated below.
-                $tmp = array();
-                $tmp['objectClass'] = array(
-                    'asteriskUser',
-                    'asteriskVoiceMailbox'
-                );
-                $tmp['voiceMailbox'] = $extension;
-                $tmp['context'] = $context;
-                $res = @ldap_mod_replace($this->_LDAP, $rdn.$branch, $tmp);
-                if (!$res) {
-                    return PEAR::raiseError("Unable to modify the user: " .
-                        ldap_error($this->_LDAP));
-                }
+                $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP),
+                                                      ldap_error($this->_LDAP));
+                Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR);
+                throw new Shout_Exception(_("Error while searching the directory.  Details have been logged for the administrator."));
+            }
 
-                # Populate the $validusers array to make the edit go smoothly
-                # below
-                $validusers[$extension] = array();
-                $validusers[$extension][$appKey] = $details[$appKey];
-
-                # The remainder of the work is done at the outside of the
-                # parent if() like a normal edit.
-
-            } elseif ($res === -1) {
-                # We must be adding a new user.
-                $entry['objectClass'] = array(
-                    'top',
-                    'person',
-                    'organizationalPerson',
-                    'inetOrgPerson',
-                    'hordePerson',
-                    'asteriskUser',
-                    'asteriskVoiceMailbox'
-                );
-
-                # Check to see if the maximum number of users for this context
-                # has been reached
-                $limits = $this->getLimits($context);
-                if (is_a($limits, "PEAR_Error")) {
-                    return $limits;
-                }
-                if (count($validusers) >= $limits['asteriskusersmax']) {
-                    return PEAR::raiseError('Maximum number of users reached.');
-                }
+            // If the extension has changed we need to perform an object rename
+            if ($extension != $details['oldextension']) {
+                $res = ldap_rename($this->_LDAP, $res['dn'], $rdn,
+                                   $this->_params['basedn'], true);
 
-                $res = @ldap_add($this->_LDAP, $rdn.$branch, $entry);
-                if (!$res) {
-                    return PEAR::raiseError('LDAP Add failed: ' .
-                        ldap_error($this->_LDAP));
+                if ($res === false) {
+                $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP),
+                                                      ldap_error($this->_LDAP));
+                Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR);
+                throw new Shout_Exception(_("Error while modifying the directory.  Details have been logged for the administrator."));
                 }
-
-                return true;
-            } elseif (is_a($res, 'PEAR_Error')) {
-                # Some kind of internal error; not even sure if this is a
-                # possible outcome or not but I'll play it safe.
-                return $res;
             }
-        }
 
-        # Anything after this point is an edit.
-
-        # Check to see if the object needs to be renamed (DN changed)
-        if ($validusers[$extension][$appKey] != $entry[$ldapKey]) {
-            $oldrdn = $ldapKey.'='.$validusers[$extension][$appKey];
-            $oldparent = SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
-            $newrdn = $ldapKey.'='.$entry[$ldapKey];
-            $res = @ldap_rename($this->_LDAP, "$oldrdn,$oldparent",
-                $newrdn, $oldparent, true);
-            if (!$res) {
-                return PEAR::raiseError('LDAP Rename failed: ' .
-                    ldap_error($this->_LDAP));
+            // Now apply the changes
+            $res = ldap_modify($this->_LDAP, $dn, $entry);
+            if ($res === false) {
+                $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP),
+                                                      ldap_error($this->_LDAP));
+                Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR);
+                throw new Shout_Exception(_("Error while modifying the directory.  Details have been logged for the administrator."));
             }
-        }
 
-        # Update the object/user
-        $dn = $ldapKey.'='.$entry[$ldapKey];
-        $dn .= ','.SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
-        $res = @ldap_modify($this->_LDAP, $dn, $entry);
-        if (!$res) {
-            return PEAR::raiseError('LDAP Modify failed: ' .
-                ldap_error($this->_LDAP));
+            return true;
+        } else {
+            // This is an add of a new extension
+            $res = ldap_add($this->_LDAP, $dn, $entry);
+            if ($res === false) {
+                $msg = sprintf('LDAP Error (%s): %s', ldap_errno($this->_LDAP),
+                                                      ldap_error($this->_LDAP));
+                Horde::logMessage($msg, __FILE__, __LINE__, PEAR_LOG_ERR);
+                throw new Shout_Exception(_("Error while modifying the directory.  Details have been logged for the administrator."));
+            }
+            return true;
         }
 
-        # We must have been successful
-        return true;
+        throw new Shout_Exception(_("Unspecified error."));
     }
 
     /**
@@ -709,7 +643,7 @@ class Shout_Driver_Ldap extends Shout_Driver
         }
 
         if (!Horde_Util::extensionExists('ldap')) {
-            throw new Horde_Exception('Required LDAP extension not found.');
+            throw new Shout_Exception('Required LDAP extension not found.');
         }
 
         Horde::assertDriverConfig($this->_params, $this->_params['class'],
@@ -722,7 +656,7 @@ class Shout_Driver_Ldap extends Shout_Driver
                 sprintf('Failed to open an LDAP connection to %s.',
                         $this->_params['hostspec']),
                 __FILE__, __LINE__, PEAR_LOG_ERR);
-            throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.');
+            throw new Shout_Exception('Internal LDAP error. Details have been logged for the administrator.');
         }
 
         /* Set hte LDAP protocol version. */
@@ -736,7 +670,7 @@ class Shout_Driver_Ldap extends Shout_Driver
                             ldap_errno($conn),
                             ldap_error($conn)),
                     __FILE__, __LINE__, PEAR_LOG_WARNING);
-                throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn));
+                throw new Shout_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn));
             }
         }
 
@@ -765,7 +699,7 @@ class Shout_Driver_Ldap extends Shout_Driver
                             @ldap_errno($conn),
                             @ldap_error($conn)),
                     __FILE__, __LINE__, PEAR_LOG_ERR);
-                throw new Horde_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn));
+                throw new Shout_Exception('Internal LDAP error. Details have been logged for the administrator.', ldap_errno($conn));
             }
         }
 
index 8eaac44..6358366 100644 (file)
@@ -69,8 +69,9 @@ class Shout_Driver_Sql extends Shout_Driver
      */
     public function getDevices($context)
     {
-        $sql = 'SELECT id, name, alias, callerid, context, mailbox, host, permit, ' .
-               'nat, secret, disallow, allow FROM %s WHERE accountcode = ?';
+        $sql = 'SELECT id, name, alias, callerid, context, mailbox, host, ' .
+               'permit, nat, secret, disallow, allow ' .
+               'FROM %s WHERE accountcode = ?';
         $sql = sprintf($sql, $this->_params['table']);
         $args = array($context);
         $result = $this->_db->query($sql, $args);
@@ -163,6 +164,7 @@ class Shout_Driver_Sql extends Shout_Driver
      */
     public function saveExtension($context, $extension, $userdetails)
     {
+        parent::saveExtension($context, $extension, $details);
         throw new Shout_Exception("Not implemented.");
     }
 
@@ -182,7 +184,7 @@ class Shout_Driver_Sql extends Shout_Driver
     /**
      * Attempts to open a persistent connection to the SQL server.
      *
-     * @throws Horde_Exception
+     * @throws Shout_Exception
      */
     protected function _connect()
     {
@@ -207,7 +209,7 @@ class Shout_Driver_Sql extends Shout_Driver
         $this->_write_db = DB::connect($this->_params,
                                        array('persistent' => !empty($this->_params['persistent'])));
         if ($this->_write_db instanceof PEAR_Error) {
-            throw Horde_Exception($this->_write_db);
+            throw Shout_Exception($this->_write_db);
         }
 
         // Set DB portability options.
@@ -226,7 +228,7 @@ class Shout_Driver_Sql extends Shout_Driver
             $this->_db = DB::connect($params,
                                      array('persistent' => !empty($params['persistent'])));
             if ($this->_db instanceof PEAR_Error) {
-                throw Horde_Exception($this->_db);
+                throw Shout_Exception($this->_db);
             }
 
             // Set DB portability options.
index 0b23911..3acb4d7 100644 (file)
@@ -23,22 +23,23 @@ class ExtensionDetailsForm extends Horde_Form {
     {
         global $shout_extensions;
         $context = $_SESSION['shout']['context'];
-        if ($vars->exists('extension')) {
+        $action = $vars->get('action');
+        if ($action == 'edit') {
             $formtitle = "Edit User";
-            $extension = $vars->get('extension');
         } else {
             $formtitle = "Add User";
         }
 
+        $extension = $vars->get('extension');
+
         parent::__construct($vars, _("$formtitle - Context: $context"));
+        
         $this->addHidden('', 'action', 'text', true);
-        $vars->set('action', 'save');
-        $this->addHidden('', 'extension', 'int', true);
-        $vars->set('newextension', $extension);
+        $this->addHidden('', 'oldextension', 'text', false);
         $this->addVariable(_("Full Name"), 'name', 'text', true);
-        $this->addVariable(_("Extension"), 'newextension', 'int', true);
+        $this->addVariable(_("Extension"), 'extension', 'int', true);
         $this->addVariable(_("E-Mail Address"), 'email', 'email', true);
-        $this->addVariable(_("Pager E-Mail Address"), 'pageremail', 'email', false);
+        //$this->addVariable(_("Pager E-Mail Address"), 'pageremail', 'email', false);
         $this->addVariable(_("PIN"), 'mailboxpin', 'int', true);
 
         return true;
@@ -54,15 +55,16 @@ class ExtensionDetailsForm extends Horde_Form {
     {
         global $shout_extensions;
 
-        $extension = $this->vars->get('extension');
+        $extension = $this->_vars->get('extension');
 
-        # FIXME: Input Validation (Text::??)
+        // FIXME: Input Validation (Text::??)
         $details = array(
-            'newextension' => $vars->get('newextension'),
-            'name' => $vars->get('name'),
-            'mailboxpin' => $vars->get('mailboxpin'),
-            'email' => $vars->get('email'),
-        );
+            'name' => $this->_vars->get('name'),
+            'oldextension' => $this->_vars->get('oldextension'),
+            'email' => $this->_vars->get('email'),
+            //'pager' => $this->_vars->get('pageremail')
+            'mailboxpin' => $this->_vars->get('mailboxpin'),
+            );
 
         $res = $shout_extensions->saveExtension($context, $extension, $details);
     }
index 8eed4aa..2dc4ebb 100644 (file)
@@ -129,8 +129,7 @@ class Shout
             $numparents--;
         }
         $test = $superadmin | $user;
-$ret = ($test & $permmask) == $permmask;
-print "Shout::checkRights() returning $ret";
+
         return ($test & $permmask) == $permmask;
     }
 }