diff --git a/lam/HISTORY b/lam/HISTORY
index 773fbf34..73aba618 100644
--- a/lam/HISTORY
+++ b/lam/HISTORY
@@ -1,4 +1,5 @@
December 2016 5.6
+ - New mechanism to replace wildcards in user edit screen. Personal/Unix support more wildcards like "$firstname".
- Windows: added support for pager, otherPager, mobile, otherMobile, company and proxyAddresses (disabled by default in server profile)
- Mail routing: enable for groups and allow to add/remove the extension
- LAM Pro:
diff --git a/lam/docs/manual-sources/howto.xml b/lam/docs/manual-sources/howto.xml
index e25333f3..1b2d319b 100644
--- a/lam/docs/manual-sources/howto.xml
+++ b/lam/docs/manual-sources/howto.xml
@@ -1005,6 +1005,9 @@ Have fun!
Mail routing: No longer added by default. Use profile editor
to activate by default for new users/groups.
+
+ Personal: no more replacement of $user/$group on user
+ upload
@@ -3306,6 +3309,12 @@ mysql> GRANT ALL PRIVILEGES ON lam_cron.* TO 'lam_cron'@'localhost';
Location
+
+ labeledURI
+
+ Web site
+
+
mail/rfc822Mailbox
@@ -3330,6 +3339,12 @@ mysql> GRANT ALL PRIVILEGES ON lam_cron.* TO 'lam_cron'@'localhost';
Organisation
+
+ ou
+
+ Organizational unit
+
+
pager
@@ -3422,6 +3437,85 @@ mysql> GRANT ALL PRIVILEGES ON lam_cron.* TO 'lam_cron'@'localhost';
+
+ Wildcards
+
+ This module provides the following wildcards (others may be
+ provided by other modules):
+
+
+
+ $firstname: First name
+
+
+
+ $lastname: Last name
+
+
+
+ $user: User name
+
+
+
+ $commonname: Common name
+
+
+
+ $email: Email address
+
+
+
+ You can use them in the following input fields on user edit
+ screen:
+
+
+
+ Common name
+
+
+
+ Description
+
+
+
+ Mail
+
+
+
+ Postal address
+
+
+
+ Registered address
+
+
+
+ Web site
+
+
+
+ Use this when some of your data always follows the same schema.
+ E.g. using "$firstname $lastname" in common name field can be used
+ like this to get "First Last". You can set the wildcards in profile
+ editor so they are automatically applied for new users.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lam/docs/manual-sources/images/mod_personal5.png b/lam/docs/manual-sources/images/mod_personal5.png
new file mode 100644
index 00000000..35be0271
Binary files /dev/null and b/lam/docs/manual-sources/images/mod_personal5.png differ
diff --git a/lam/docs/manual-sources/images/mod_personal6.png b/lam/docs/manual-sources/images/mod_personal6.png
new file mode 100644
index 00000000..e3648113
Binary files /dev/null and b/lam/docs/manual-sources/images/mod_personal6.png differ
diff --git a/lam/lib/baseModule.inc b/lam/lib/baseModule.inc
index b0f5a7cb..4644664f 100644
--- a/lam/lib/baseModule.inc
+++ b/lam/lib/baseModule.inc
@@ -1951,6 +1951,16 @@ abstract class baseModule {
return ($this->moduleSettings[$optionName][0] == 'true');
}
+ /**
+ * Returns a list of wildcards that can be replaced in input fileds.
+ * E.g. "$firstname$" is replaced with "givenName" attribute value.
+ *
+ * @return array replacements as wildcard => value
+ */
+ public function getWildCardReplacements() {
+ return array();
+ }
+
}
/**
diff --git a/lam/lib/modules.inc b/lam/lib/modules.inc
index f17cf003..e54bb1b1 100644
--- a/lam/lib/modules.inc
+++ b/lam/lib/modules.inc
@@ -2143,6 +2143,62 @@ class accountContainer {
return $this->cachedOUs;
}
+ /**
+ * Replaces POST data with wildcard values from modules.
+ *
+ * @param array $keyPrefixes POST keys as full name or prefix (e.g. "key" matches "key1")
+ */
+ public function replaceWildcardsInPOST($keyPrefixes) {
+ $replacements = array();
+ foreach ($this->module as $module) {
+ $replacements = array_merge($replacements, $module->getWildCardReplacements());
+ }
+ while (true) {
+ if (!$this->replaceWildcards($replacements, $keyPrefixes, $_POST)) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Replaces wildcards in an array.
+ *
+ * @param array $replacements replacements (key => value)
+ * @param array $keyPrefixes prefixes of $data array keys that should be replaced
+ * @param array $data data array
+ * @return boolean replacement done
+ */
+ private function replaceWildcards($replacements, $keyPrefixes, &$data) {
+ $found = false;
+ foreach ($data as $key => $value) {
+ foreach ($keyPrefixes as $keyPrefix) {
+ if (strpos($key, $keyPrefix) === 0) {
+ $found = $this->doReplace($replacements, $data[$key]) || $found;
+ }
+ }
+ }
+ return $found;
+ }
+
+ /**
+ * Replaces wildcards in a value.
+ *
+ * @param array $replacements replacements (key => value)
+ * @param String $value value to perform replacements
+ * @return boolean replacement done
+ */
+ private function doReplace($replacements, &$value) {
+ $found = false;
+ foreach ($replacements as $replKey => $replValue) {
+ $searchString = '$' . $replKey;
+ if (strpos($value, $searchString) !== false) {
+ $found = true;
+ $value = str_replace($searchString, $replValue, $value);
+ }
+ }
+ return $found;
+ }
+
/**
* Encrypts sensitive data before storing in session.
*
diff --git a/lam/lib/modules/inetOrgPerson.inc b/lam/lib/modules/inetOrgPerson.inc
index 5e124534..15df66e0 100644
--- a/lam/lib/modules/inetOrgPerson.inc
+++ b/lam/lib/modules/inetOrgPerson.inc
@@ -171,6 +171,9 @@ class inetOrgPerson extends baseModule implements passwordService {
'ou', 'description', 'uid');
// profile elements
$profileElements = array();
+ if (!$this->isUnixActive()) {
+ $profileElements[] = new htmlTableExtendedInputField(_('Common name'), 'inetOrgPerson_cn', null, 'cn');
+ }
if (!$this->isBooleanConfigOptionSet('inetOrgPerson_hideInitials')) {
$profileElements[] = new htmlTableExtendedInputField(_('Initials'), 'inetOrgPerson_initials', null, 'initials');
}
@@ -243,6 +246,9 @@ class inetOrgPerson extends baseModule implements passwordService {
$return['profile_options'] = $profileContainer;
}
// profile checks and mappings
+ if (!$this->isUnixActive()) {
+ $return['profile_mappings']['inetOrgPerson_cn'] = 'cn';
+ }
if (!$this->isBooleanConfigOptionSet('inetOrgPerson_hideInitials')) {
$return['profile_mappings']['inetOrgPerson_initials'] = 'initials';
}
@@ -740,12 +746,11 @@ class inetOrgPerson extends baseModule implements passwordService {
),
'mail' => array (
"Headline" => _("Email address"), 'attr' => 'mail',
- "Text" => _("The user's email address.") . ' ' . _('You can use "$user", "$firstname" and "$lastname" as wildcards for user name, first and last name.')
+ "Text" => _("The user's email address.")
),
'mailList' => array (
"Headline" => _("Email address"), 'attr' => 'mail',
"Text" => _("The user's email address.") . ' ' . _('Multiple values are separated by semicolon.')
- . ' ' . _('You can use "$user", "$firstname" and "$lastname" as wildcards for user name, first and last name.')
),
"mailPassword" => array (
"Headline" => _("Send password via mail"),
@@ -934,22 +939,6 @@ class inetOrgPerson extends baseModule implements passwordService {
if (!$this->getAccountContainer()->isNewAccount && !in_array('inetOrgPerson', $this->getAccountContainer()->attributes_orig['objectClass'])) {
return array();
}
- // replace $user in email
- if (!empty($this->attributes['mail'][0])) {
- $user = null;
- if ($this->getAccountContainer()->getAccountModule('posixAccount') != null) {
- $attrs = $this->getAccountContainer()->getAccountModule('posixAccount')->getAttributes();
- $user = $attrs['uid'][0];
- }
- elseif (!empty($this->attributes['uid'][0])) {
- $user = $this->attributes['uid'][0];
- }
- if (!empty($user)) {
- foreach ($this->attributes['mail'] as &$mail) {
- $mail = str_replace('$user', $user, $mail);
- }
- }
- }
$return = $this->getAccountContainer()->save_module_attributes($this->attributes, $this->orig);
// postalAddress, registeredAddress, facsimileTelephoneNumber and jpegPhoto need special removing
if (isset($return[$this->getAccountContainer()->dn_orig]['remove']['postalAddress'])) {
@@ -1037,7 +1026,12 @@ class inetOrgPerson extends baseModule implements passwordService {
*/
function process_attributes() {
$errors = array();
- $replacements = array('$lastname' => 'sn', '$firstname' => 'givenName');
+ $keysToReplace = array('mail', 'description', 'postalAddress', 'cn',
+ 'registeredAddress', 'labeledURI');
+ if ($this->isUnixActive()) {
+ $keysToReplace[] = 'uid';
+ }
+ $this->getAccountContainer()->replaceWildcardsInPOST($keysToReplace);
// add parent object classes
if ($this->getAccountContainer()->isNewAccount) {
if (!in_array('organizationalPerson', $this->attributes['objectClass'])) {
@@ -1069,11 +1063,6 @@ class inetOrgPerson extends baseModule implements passwordService {
$this->processMultiValueInputTextField('mail', $errors, 'email');
if (!empty($this->attributes['mail'])) {
foreach ($this->attributes['mail'] as &$mail) {
- foreach ($replacements as $wildcard => $key) {
- if (!empty($this->attributes[$key][0])) {
- $mail = str_replace($wildcard, $this->attributes[$key][0], $mail);
- }
- }
if (empty($this->orig['mail']) || !in_array($mail, $this->orig['mail'])) {
if ($this->emailExists($mail)) {
$msg = $this->messages['mail'][1];
@@ -2178,7 +2167,6 @@ class inetOrgPerson extends baseModule implements passwordService {
*/
function build_uploadAccounts($rawAccounts, $ids, &$partialAccounts, $selectedModules) {
$errors = array();
- $replacements = array();
// get list of existing users
$existingUsers = searchLDAPByAttribute('uid', '*', 'inetOrgPerson', array('uid'), array('user'));
for ($e = 0; $e < sizeof($existingUsers); $e++) {
@@ -2189,7 +2177,6 @@ class inetOrgPerson extends baseModule implements passwordService {
// last name
if (get_preg($rawAccounts[$i][$ids['inetOrgPerson_lastName']], 'realname')) {
$partialAccounts[$i]['sn'] = trim($rawAccounts[$i][$ids['inetOrgPerson_lastName']]);
- $replacements['$lastname'] = $partialAccounts[$i]['sn'];
}
else {
$errMsg = $this->messages['lastname'][1];
@@ -2200,7 +2187,6 @@ class inetOrgPerson extends baseModule implements passwordService {
if ($rawAccounts[$i][$ids['inetOrgPerson_firstName']] != "") {
if (get_preg($rawAccounts[$i][$ids['inetOrgPerson_firstName']], 'realname')) {
$partialAccounts[$i]['givenName'] = trim($rawAccounts[$i][$ids['inetOrgPerson_firstName']]);
- $replacements['$firstname'] = $partialAccounts[$i]['givenName'];
}
else {
$errMsg = $this->messages['givenName'][1];
@@ -2218,7 +2204,6 @@ class inetOrgPerson extends baseModule implements passwordService {
}
elseif (get_preg($rawAccounts[$i][$ids['inetOrgPerson_userName']], 'username')) {
$partialAccounts[$i]['uid'] = $rawAccounts[$i][$ids['inetOrgPerson_userName']];
- $replacements['$user'] = $partialAccounts[$i]['uid'];
}
else {
$errMsg = $this->messages['uid'][1];
@@ -2300,9 +2285,6 @@ class inetOrgPerson extends baseModule implements passwordService {
$this->mapSimpleUploadField($rawAccounts, $ids, $partialAccounts, $i, 'inetOrgPerson_pager', 'pager', 'telephone', $this->messages['pager'][1], $errors, '/;[ ]*/');
// eMail
if (isset($ids['inetOrgPerson_email']) && ($rawAccounts[$i][$ids['inetOrgPerson_email']] != "")) {
- foreach ($replacements as $wildcard => $value) {
- $rawAccounts[$i][$ids['inetOrgPerson_email']] = str_replace($wildcard, $value, $rawAccounts[$i][$ids['inetOrgPerson_email']]);
- }
$mailList = preg_split('/;[ ]*/', trim($rawAccounts[$i][$ids['inetOrgPerson_email']]));
$partialAccounts[$i]['mail'] = $mailList;
for ($x = 0; $x < sizeof($mailList); $x++) {
@@ -3810,6 +3792,54 @@ class inetOrgPerson extends baseModule implements passwordService {
return in_array('posixAccount', $modules);
}
+ /**
+ * Returns a list of wildcards that can be replaced in input fileds.
+ * E.g. "$firstname$" is replaced with "givenName" attribute value.
+ *
+ * @return array replacements as wildcard => value
+ */
+ public function getWildCardReplacements() {
+ $replacements = array();
+ // first name
+ if (!empty($_POST['givenName'])) {
+ $replacements['firstname'] = $_POST['givenName'];
+ }
+ elseif (!empty($this->attributes['givenName'][0])) {
+ $replacements['firstname'] = $this->attributes['givenName'][0];
+ }
+ // last name
+ if (!empty($_POST['sn'])) {
+ $replacements['lastname'] = $_POST['sn'];
+ }
+ elseif (!empty($this->attributes['sn'][0])) {
+ $replacements['lastname'] = $this->attributes['sn'][0];
+ }
+ // user name
+ if (!$this->isUnixActive()) {
+ if (!empty($_POST['uid'])) {
+ $replacements['user'] = $_POST['uid'];
+ }
+ elseif (!empty($this->attributes['uid'][0])) {
+ $replacements['user'] = $this->attributes['uid'][0];
+ }
+ }
+ // cn
+ if (!empty($_POST['cn_0'])) {
+ $replacements['commonname'] = $_POST['cn_0'];
+ }
+ elseif (!empty($this->attributes['cn'][0])) {
+ $replacements['commonname'] = $this->attributes['cn'][0];
+ }
+ // mail
+ if (!empty($_POST['mail_0'])) {
+ $replacements['email'] = $_POST['mail_0'];
+ }
+ elseif (!empty($this->attributes['mail'][0])) {
+ $replacements['email'] = $this->attributes['mail'][0];
+ }
+ return $replacements;
+ }
+
}
?>
diff --git a/lam/lib/modules/posixAccount.inc b/lam/lib/modules/posixAccount.inc
index 4ac81d64..04f396a4 100644
--- a/lam/lib/modules/posixAccount.inc
+++ b/lam/lib/modules/posixAccount.inc
@@ -471,7 +471,7 @@ class posixAccount extends baseModule implements passwordService {
),
'homeDirectory' => array(
"Headline" => _("Home directory"), 'attr' => $this->getHomedirAttrName(),
- "Text" => _('$user and $group will be replaced with user name and primary group name.')
+ "Text" => _("Please enter the path to the user's home directory.")
),
'userPassword' => array(
"Headline" => _("Password"),
@@ -990,6 +990,8 @@ class posixAccount extends baseModule implements passwordService {
* @return array list of info/error messages
*/
function process_attributes() {
+ $keysToReplace = array('cn', 'gecos', 'homeDirectory');
+ $this->getAccountContainer()->replaceWildcardsInPOST($keysToReplace);
$errors = array();
if (isset($_POST['addObjectClass'])) {
if (!isset($this->attributes['objectClass'])) {
@@ -1160,11 +1162,6 @@ class posixAccount extends baseModule implements passwordService {
if ($this->get_scope()=='host') $errors[] = $this->messages['uid'][6];
}
if ($this->get_scope()=='user') {
- $this->attributes[$homedirAttrName][0] = str_replace('$group', $this->getGroupName($this->attributes['gidNumber'][0]), $this->attributes[$homedirAttrName][0]);
- if ($this->attributes['uid'][0] != '') {
- $this->attributes[$homedirAttrName][0] = str_replace('$user', $this->attributes['uid'][0], $this->attributes[$homedirAttrName][0]);
- }
- if ($this->attributes[$homedirAttrName][0] != $_POST['homeDirectory']) $errors[] = array('INFO', _('Home directory'), _('Replaced $user or $group in homedir.'));
// Check if Username contains only valid characters
if (!get_preg($this->attributes['uid'][0], 'username'))
$errors[] = $this->messages['uid'][2];
@@ -3459,6 +3456,31 @@ class posixAccount extends baseModule implements passwordService {
return $this->isBooleanConfigOptionSet('posixAccount_noObjectClass');
}
+ /**
+ * Returns a list of wildcards that can be replaced in input fileds.
+ * E.g. "$firstname$" is replaced with "givenName" attribute value.
+ *
+ * @return array replacements as wildcard => value
+ */
+ public function getWildCardReplacements() {
+ $replacements = array();
+ // user name
+ if (!empty($_POST['uid'])) {
+ $replacements['user'] = $_POST['uid'];
+ }
+ elseif (!empty($this->attributes['uid'][0])) {
+ $replacements['user'] = $this->attributes['uid'][0];
+ }
+ // group name
+ if (!empty($_POST['gidNumber'])) {
+ $replacements['group'] = $this->getGroupName($_POST['gidNumber']);
+ }
+ elseif (!empty($this->attributes['gidNumber'][0])) {
+ $replacements['group'] = $this->getGroupName($this->attributes['gidNumber'][0]);
+ }
+ return $replacements;
+ }
+
}
?>