From af157c3218415abdd81a57adc42dda2351465682 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Mon, 27 Jul 2015 16:52:55 +0000 Subject: [PATCH] * Addressbook: custom fields of accounts enabled via own-account-acl were not editable --- addressbook/inc/class.addressbook_bo.inc.php | 20 +++-- .../inc/class.addressbook_tracking.inc.php | 4 +- ...lass.etemplate_widget_customfields.inc.php | 90 +++++++++---------- etemplate/js/et2_extension_customfields.js | 5 +- 4 files changed, 63 insertions(+), 56 deletions(-) diff --git a/addressbook/inc/class.addressbook_bo.inc.php b/addressbook/inc/class.addressbook_bo.inc.php index 2d0e84b4bf..5fc7df43b1 100755 --- a/addressbook/inc/class.addressbook_bo.inc.php +++ b/addressbook/inc/class.addressbook_bo.inc.php @@ -925,6 +925,11 @@ class addressbook_bo extends addressbook_so } if (isset($contact['org_name'])) $contact['n_fileas'] = $this->fileas($contact, null, false); + // Get old record for tracking changes + if (!isset($old) && $isUpdate) + { + $old = $this->read($contact['id']); + } $to_write = $contact; // (non-admin) user editing his own account, make sure he does not change fields he is not allowed to (eg. via SyncML or xmlrpc) if (!$ignore_acl && !$contact['owner'] && !$this->is_admin($contact)) @@ -933,16 +938,19 @@ class addressbook_bo extends addressbook_so { if (!in_array($field,$this->own_account_acl) && !in_array($field,array('id','owner','account_id','modified','modifier'))) { - unset($to_write[$field]); // user is now allowed to change that + // user is not allowed to change that + if ($old) + { + $to_write[$field] = $old[$field]; + } + else + { + unset($to_write[$field]); + } } } } - // Get old record for tracking changes - if (!isset($old) && $isUpdate) - { - $old = $this->read($contact['id']); - } // IF THE OLD ENTRY IS A ACCOUNT, dont allow to change the owner/location // maybe we need that for id and account_id as well. if (is_array($old) && (!isset($old['owner']) || empty($old['owner']))) diff --git a/addressbook/inc/class.addressbook_tracking.inc.php b/addressbook/inc/class.addressbook_tracking.inc.php index 9187aa233d..62812f97fe 100644 --- a/addressbook/inc/class.addressbook_tracking.inc.php +++ b/addressbook/inc/class.addressbook_tracking.inc.php @@ -150,9 +150,9 @@ class addressbook_tracking extends bo_tracking foreach(array('adr_one_countryname' => 'adr_one_countrycode', 'adr_two_countryname' => 'adr_two_countrycode') as $name => $code) { // Only codes involved, but old text name is automatically added when loaded - if($old[$code] && $data[$code]) + if($old[$code] && $data[$code] && ($key = array_search($name, $changed_fields)) !== false) { - unset($changed_fields[array_search($name, $changed_fields)]); + unset($changed_fields[$key]); continue; } diff --git a/etemplate/inc/class.etemplate_widget_customfields.inc.php b/etemplate/inc/class.etemplate_widget_customfields.inc.php index 8cc0287017..1a7ec2b118 100644 --- a/etemplate/inc/class.etemplate_widget_customfields.inc.php +++ b/etemplate/inc/class.etemplate_widget_customfields.inc.php @@ -347,56 +347,56 @@ class etemplate_widget_customfields extends etemplate_widget_transformer $form_name = self::GLOBAL_ID; } - if (!$this->is_readonly($cname, $form_name)) + $all_readonly = $this->is_readonly($cname, $form_name); + $value_in = self::get_array($content, $form_name); + // if we have no id / use self::GLOBAL_ID, we have to set $value_in in global namespace for regular widgets validation to find + if (!$this->id) $content = array_merge($content, $value_in); + //error_log(__METHOD__."($cname, ...) form_name=$form_name, use-private={$this->attrs['use-private']}, value_in=".array2string($value_in)); + $customfields =& $this->getElementAttribute(self::GLOBAL_VALS, 'customfields'); + if(is_array($value_in)) { - $value_in = self::get_array($content, $form_name); - // if we have no id / use self::GLOBAL_ID, we have to set $value_in in global namespace for regular widgets validation to find - if (!$this->id) $content = array_merge($content, $value_in); - //error_log(__METHOD__."($cname, ...) form_name=$form_name, use-private={$this->attrs['use-private']}, value_in=".array2string($value_in)); - $customfields =& $this->getElementAttribute(self::GLOBAL_VALS, 'customfields'); - if(is_array($value_in)) + foreach($value_in as $field => $value) { - foreach($value_in as $field => $value) + $field_settings = $customfields[$fname=substr($field,1)]; + + if ((string)$this->attrs['use-private'] !== '' && // are only (non-)private fields requested + (boolean)$field_settings['private'] != ($this->attrs['use-private'] != '0')) { - $field_settings = $customfields[$fname=substr($field,1)]; - - if ((string)$this->attrs['use-private'] !== '' && // are only (non-)private fields requested - (boolean)$field_settings['private'] != ($this->attrs['use-private'] != '0')) - { - continue; - } - - // check if single field is set readonly, used in apps as it was only way to make cfs readonly in old eT - if ($this->is_readonly($form_name != self::GLOBAL_ID ? $form_name : $cname, $field)) - { - continue; - } - // run validation method of widget implementing this custom field - $widget = $this->_widget($fname, $field_settings); - // widget has no validate method, eg. is only displaying stuff --> nothing to validate - if (!method_exists($widget, 'validate')) continue; - $widget->validate($form_name != self::GLOBAL_ID ? $form_name : $cname, $expand, $content, $validated); - if ($field_settings['needed'] && (is_array($value) ? !$value : (string)$value === '')) - { - self::set_validation_error($field,lang('Field must not be empty !!!'),''); - } - $field_name = $this->id[0] == self::$prefix && $customfields[substr($this->id,1)] ? $this->id : self::form_name($form_name != self::GLOBAL_ID ? $form_name : $cname, $field); - $valid =& self::get_array($validated, $field_name, true); - - if (is_array($valid)) $valid = implode(',', $valid); - // NULL is valid for most fields, but not custom fields due to backend handling - // See so_sql_cf->save() - if (is_null($valid)) $valid = false; - //error_log(__METHOD__."() $field_name: ".array2string($value).' --> '.array2string($valid)); + continue; } + + // check if single field is set readonly, used in apps as it was only way to make cfs readonly in old eT + // single fields set to false in $readonly overwrite a global __ALL__ + $cf_readonly = $this->is_readonly($form_name != self::GLOBAL_ID ? $form_name : $cname, $field); + if ($cf_readonly || $all_readonly && $cf_readonly !== false) + { + continue; + } + // run validation method of widget implementing this custom field + $widget = $this->_widget($fname, $field_settings); + // widget has no validate method, eg. is only displaying stuff --> nothing to validate + if (!method_exists($widget, 'validate')) continue; + $widget->validate($form_name != self::GLOBAL_ID ? $form_name : $cname, $expand, $content, $validated); + if ($field_settings['needed'] && (is_array($value) ? !$value : (string)$value === '')) + { + self::set_validation_error($field,lang('Field must not be empty !!!'),''); + } + $field_name = $this->id[0] == self::$prefix && $customfields[substr($this->id,1)] ? $this->id : self::form_name($form_name != self::GLOBAL_ID ? $form_name : $cname, $field); + $valid =& self::get_array($validated, $field_name, true); + + if (is_array($valid)) $valid = implode(',', $valid); + // NULL is valid for most fields, but not custom fields due to backend handling + // See so_sql_cf->save() + if (is_null($valid)) $valid = false; + //error_log(__METHOD__."() $field_name: ".array2string($value).' --> '.array2string($valid)); } - elseif ($this->type == 'customfields-types') - { - // Transformation doesn't handle validation - $valid =& self::get_array($validated, $this->id ? $form_name : $field, true); - if (true) $valid = $value_in; - //error_log(__METHOD__."() $form_name $field: ".array2string($value).' --> '.array2string($value)); - } + } + elseif ($this->type == 'customfields-types') + { + // Transformation doesn't handle validation + $valid =& self::get_array($validated, $this->id ? $form_name : $field, true); + if (true) $valid = $value_in; + //error_log(__METHOD__."() $form_name $field: ".array2string($value).' --> '.array2string($value)); } } } diff --git a/etemplate/js/et2_extension_customfields.js b/etemplate/js/et2_extension_customfields.js index 57d3c6eeda..dcbae50553 100644 --- a/etemplate/js/et2_extension_customfields.js +++ b/etemplate/js/et2_extension_customfields.js @@ -200,8 +200,7 @@ var et2_customfields_list = et2_valueWidget.extend([et2_IDetachedDOM, et2_IInput 'id': id, 'statustext': field.help, 'needed': field.needed, - 'readonly': this.options.readonly || - this.getArrayMgr("readonlys").isReadOnly(id), + 'readonly': this.getArrayMgr("readonlys").isReadOnly(id, null, this.options.readonly), 'value': this.options.value[this.prefix+field_name] }; // Can't have a required readonly, it will warn & be removed later, so avoid the warning @@ -297,7 +296,7 @@ var et2_customfields_list = et2_valueWidget.extend([et2_IDetachedDOM, et2_IInput // Set the value for this element var contentMgr = this.getArrayMgr("content"); if (contentMgr != null) { - var val = contentMgr.getEntry(this.id); + var val = contentMgr.getEntry(this.id); _attrs["value"] = {}; if (val !== null) {