diff --git a/include/ajax.forms.php b/include/ajax.forms.php index 9ca601e33020d9c0f3ea1e669bbc4d405217df5e..c25570e095754f8e4237de353c817aae8259269e 100644 --- a/include/ajax.forms.php +++ b/include/ajax.forms.php @@ -32,7 +32,8 @@ class DynamicFormsAjaxAPI extends AjaxController { if (!$form->hasAnyVisibleFields()) continue; ob_start(); - $form->getForm($_SESSION[':form-data'])->render(!$client); + $form->getForm($_SESSION[':form-data'])->render(!$client, false, + array('mode' => 'create')); $html .= ob_get_clean(); ob_start(); print $form->getMedia(); diff --git a/include/ajax.orgs.php b/include/ajax.orgs.php index 9c2a2b207c11ba72e8b6c7fa259670d0b4b6a0d7..d3ffc8b9dec2b994ae95efd133104a4860d308dc 100644 --- a/include/ajax.orgs.php +++ b/include/ajax.orgs.php @@ -93,7 +93,7 @@ class OrgsAjaxAPI extends AjaxController { $errors = array(); if($org->update($_POST, $errors)) - Http::response(201, $org->to_json()); + Http::response(201, $org->to_json(), 'application/json'); $forms = $org->getForms(); @@ -162,7 +162,7 @@ class OrgsAjaxAPI extends AjaxController { } if (!$info['error'] && $user && $user->setOrganization($org)) - Http::response(201, $user->to_json()); + Http::response(201, $user->to_json(), 'application/json'); elseif (!$info['error']) $info['error'] = sprintf('%s - %s', __('Unable to add user to the organization'), __('Please try again!')); @@ -230,7 +230,7 @@ class OrgsAjaxAPI extends AjaxController { if ($_POST) { $form = OrganizationForm::getDefaultForm()->getForm($_POST); if (($org = Organization::fromForm($form))) - Http::response(201, $org->to_json()); + Http::response(201, $org->to_json(), 'application/json'); $info = array('error' =>sprintf('%s - %s', __('Error adding organization'), __('Please try again!'))); } @@ -274,7 +274,7 @@ class OrgsAjaxAPI extends AjaxController { $info += array('title' => __('Organization Lookup')); if ($_POST && ($org = Organization::lookup($_POST['orgid']))) { - Http::response(201, $org->to_json()); + Http::response(201, $org->to_json(), 'application/json'); } ob_start(); diff --git a/include/ajax.users.php b/include/ajax.users.php index 328b93cf0e1d1167797ad29fcda7a0d6a1b8da8b..459c4654286a5ad2bac46bcf1aba222caaf2f380 100644 --- a/include/ajax.users.php +++ b/include/ajax.users.php @@ -168,7 +168,7 @@ class UsersAjaxAPI extends AjaxController { $errors = array(); if ($user->updateInfo($_POST, $errors, true) && !$errors) - Http::response(201, $user->to_json()); + Http::response(201, $user->to_json(), 'application/json'); $forms = $user->getForms(); include(STAFFINC_DIR . 'templates/user.tmpl.php'); @@ -271,7 +271,7 @@ class UsersAjaxAPI extends AjaxController { function getUser($id=false) { if(($user=User::lookup(($id) ? $id : $_REQUEST['id']))) - Http::response(201, $user->to_json()); + Http::response(201, $user->to_json(), 'application/json'); $info = array('error' => sprintf(__('%s: Unknown or invalid ID.'), _N('end user', 'end users', 1))); @@ -297,7 +297,7 @@ class UsersAjaxAPI extends AjaxController { $info['title'] = __('Add New User'); $form = UserForm::getUserForm()->getForm($_POST); if (($user = User::fromForm($form))) - Http::response(201, $user->to_json()); + Http::response(201, $user->to_json(), 'application/json'); $info['error'] = sprintf('%s - %s', __('Error adding user'), __('Please try again!')); } @@ -433,7 +433,7 @@ class UsersAjaxAPI extends AjaxController { } if ($org && $user->setOrganization($org)) - Http::response(201, $org->to_json()); + Http::response(201, $org->to_json(), 'application/json'); elseif (! $info['error']) $info['error'] = __('Unable to add user to organization.') .' '.__('Correct any errors below and try again.'); diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index 9e5ece6717585e697b13df71265dfec22bcaff05..4cb03f56efdcc2452a0e55314252e8b587073440 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -1098,16 +1098,18 @@ class DynamicFormEntry extends VerySimpleModel { return !$this->_errors; } - function isValidForClient() { - $filter = function($f) { - return $f->isVisibleToUsers(); + function isValidForClient($update=false) { + $filter = function($f) use($update) { + return $update ? $f->isEditableToUsers() : + $f->isVisibleToUsers(); }; return $this->isValid($filter); } - function isValidForStaff() { - $filter = function($f) { - return $f->isVisibleToStaff(); + function isValidForStaff($update=false) { + $filter = function($f) use($update) { + return $update ? $f->isEditableToStaff() : + $f->isVisibleToStaff(); }; return $this->isValid($filter); } @@ -1237,6 +1239,15 @@ class DynamicFormEntry extends VerySimpleModel { } } + /** + * Save the form entry and all associated answers. + * + */ + + function save($refetch=false) { + return $this->saveAnswers(null, $refetch); + } + /** * Save the form entry and all associated answers. * @@ -1244,7 +1255,8 @@ class DynamicFormEntry extends VerySimpleModel { * (mixed) FALSE if updated failed, otherwise the number of dirty answers * which were save is returned (which may be ZERO). */ - function save($refetch=false) { + + function saveAnswers($isEditable=null, $refetch=false) { if (count($this->dirty)) $this->set('updated', new SqlFunction('NOW')); @@ -1254,12 +1266,12 @@ class DynamicFormEntry extends VerySimpleModel { $dirty = 0; foreach ($this->getAnswers() as $a) { $field = $a->getField(); - // Don't save answers for presentation-only fields or fields - // which are stored elsewhere - if (!$field->hasData() || !$field->isStorable() - || $field->isPresentationOnly() - ) { + // which are stored elsewhere or those which are not editable + if (!$field->hasData() + || !$field->isStorable() + || $field->isPresentationOnly() + || ($isEditable && !$isEditable($field))) { continue; } // Set the entry here so that $field->getClean() can use the diff --git a/include/class.forms.php b/include/class.forms.php index c03b22dea807b37223d021a44d5916b598d15109..3976cd8894b6d8f342766fb4165d74ff4ebf524b 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -43,7 +43,7 @@ class Form { $this->id = $options['id']; // Use POST data if source was not specified - $this->_source = ($source) ? $source : $_POST; + $this->_source = $source ?: $_POST; } function getFormId() { @@ -89,6 +89,28 @@ class Form { return $this->getField($name); } + function hasAnyEnabledFields() { + return $this->hasAnyVisibleFields(false); + } + + function hasAnyVisibleFields($user=false) { + $visible = 0; + $isstaff = $user instanceof Staff; + foreach ($this->getFields() as $F) { + if (!$user) { + // Assume hasAnyEnabledFields + if ($F->isEnabled()) + $visible++; + } elseif($isstaff) { + if ($F->isVisibleToStaff()) + $visible++; + } elseif ($F->isVisibleToUsers()) { + $visible++; + } + } + return $visible > 0; + } + function getTitle() { return $this->title; } function getInstructions() { return $this->instructions; } function getSource() { return $this->_source; } @@ -836,7 +858,7 @@ class FormField { * Returns an HTML friendly value for the data in the field. */ function display($value) { - return Format::htmlchars($this->toString($value)); + return Format::htmlchars($this->toString($value ?: $this->value)); } /** diff --git a/include/class.ticket.php b/include/class.ticket.php index 37c80c73c669fa1b9f59dbbebfed6eb563b3fc3d..a3f33f0521c2bb510b7e6a24fd07145c6b14b577 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -3300,22 +3300,25 @@ implements RestrictedAccess, Threadable, Searchable { if (!$this->save()) return false; - $vars['note'] = ThreadEntryBody::clean($vars['note']); + $vars['note'] = ThreadEntryBody::clean($vars['note']); if ($vars['note']) $this->logNote(_S('Ticket Updated'), $vars['note'], $thisstaff); // Update dynamic meta-data - foreach ($forms as $f) { - if ($C = $f->getChanges()) + foreach ($forms as $form) { + if ($C = $form->getChanges()) $changes['fields'] = ($changes['fields'] ?: array()) + $C; // Drop deleted forms - $idx = array_search($f->getId(), $vars['forms']); + $idx = array_search($form->getId(), $vars['forms']); if ($idx === false) { - $f->delete(); + $form->delete(); } else { - $f->set('sort', $idx); - $f->save(); + $form->set('sort', $idx); + $form->saveAnswers(function($f) { + return $f->isVisibleToStaff() + && $f->isEditableToStaff(); } + ); } } @@ -3358,7 +3361,10 @@ implements RestrictedAccess, Threadable, Searchable { __($field->getLabel())); else { if ($field->answer) { - if (!$field->save()) + if (!$field->isEditableToStaff()) + $errors['field'] = sprintf(__('%s can not be edited'), + __($field->getLabel())); + elseif (!$field->save()) $errors['field'] = __('Unable to update field'); $changes['fields'] = array($field->getId() => $changes); } else { diff --git a/include/class.user.php b/include/class.user.php index 8d6bd1a7bb76f9197d1b6b1844271aec337121d2..36e1df54848c17b7e8de08268135820cb0079ad0 100644 --- a/include/class.user.php +++ b/include/class.user.php @@ -359,7 +359,7 @@ implements TemplateVariable, Searchable { 'email' => (string) $this->getEmail(), 'phone' => (string) $this->getPhoneNumber()); - return JsonDataEncoder::encode($info); + return Format::json_encode($info); } function __toString() { @@ -451,19 +451,20 @@ implements TemplateVariable, Searchable { return $vars; } - function getForms($data=null) { + function getForms($data=null, $cb=null) { if (!isset($this->_forms)) { $this->_forms = array(); + $cb = $cb ?: function ($f) use($data) { return ($data); }; foreach ($this->getDynamicData() as $entry) { $entry->addMissingFields(); - if(!$data - && ($form = $entry->getDynamicForm()) + if(($form = $entry->getDynamicForm()) && $form->get('type') == 'U' ) { + foreach ($entry->getFields() as $f) { - if ($f->get('name') == 'name') + if ($f->get('name') == 'name' && !$cb($f)) $f->value = $this->getFullName(); - elseif ($f->get('name') == 'email') + elseif ($f->get('name') == 'email' && !$cb($f)) $f->value = $this->getEmail(); } } @@ -529,17 +530,23 @@ implements TemplateVariable, Searchable { function updateInfo($vars, &$errors, $staff=false) { + + $isEditable = function ($f) use($staff) { + return ($staff ? $f->isEditableToStaff() : + $f->isEditableToUsers()); + }; $valid = true; - $forms = $this->getForms($vars); + $forms = $this->getForms($vars, $isEditable); foreach ($forms as $entry) { $entry->setSource($vars); - if ($staff && !$entry->isValidForStaff()) + if ($staff && !$entry->isValidForStaff(true)) $valid = false; - elseif (!$staff && !$entry->isValidForClient()) + elseif (!$staff && !$entry->isValidForClient(true)) $valid = false; elseif ($entry->getDynamicForm()->get('type') == 'U' && ($f=$entry->getField('email')) - && $f->getClean() + && $isEditable($f) + && $f->getClean() && ($u=User::lookup(array('emails__address'=>$f->getClean()))) && $u->id != $this->getId()) { $valid = false; @@ -558,7 +565,7 @@ implements TemplateVariable, Searchable { foreach ($forms as $entry) { if ($entry->getDynamicForm()->get('type') == 'U') { // Name field - if (($name = $entry->getField('name'))) { + if (($name = $entry->getField('name')) && $isEditable($name) ) { $name = $name->getClean(); if (is_array($name)) $name = implode(', ', $name); @@ -566,14 +573,15 @@ implements TemplateVariable, Searchable { } // Email address field - if (($email = $entry->getField('email'))) { + if (($email = $entry->getField('email')) + && $isEditable($email)) { $this->default_email->address = $email->getClean(); $this->default_email->save(); } } - // DynamicFormEntry::save returns the number of answers updated - if ($entry->save()) { + // DynamicFormEntry::saveAnswers returns the number of answers updated + if ($entry->saveAnswers($isEditable)) { $this->updated = SqlFunction::NOW(); } } diff --git a/include/client/open.inc.php b/include/client/open.inc.php index 9900e2fe272e71cdc45afda0723f62f660d1504c..021de566acdb8dda91ff475a13b942e161cd650e 100644 --- a/include/client/open.inc.php +++ b/include/client/open.inc.php @@ -42,7 +42,7 @@ if ($info['topicId'] && ($topic=Topic::lookup($info['topicId']))) { if (!$thisclient) { $uform = UserForm::getUserForm()->getForm($_POST); if ($_POST) $uform->isValid(); - $uform->render(false); + $uform->render(false, false, array('mode' => 'create')); } else { ?> <tr><td colspan="2"><hr /></td></tr> diff --git a/include/client/templates/dynamic-form.tmpl.php b/include/client/templates/dynamic-form.tmpl.php index cfde56a64e9d00c27adc7ed06290c51cb0b69346..e7e017a5999e4b84705ecf0c59de4a4a8a195045 100644 --- a/include/client/templates/dynamic-form.tmpl.php +++ b/include/client/templates/dynamic-form.tmpl.php @@ -1,8 +1,11 @@ <?php - // Form headline and deck with a horizontal divider above and an extra - // space below. - // XXX: Would be nice to handle the decoration with a CSS class - ?> +// Return if no visible fields +global $thisclient; +if (!$form->hasAnyVisibleFields($thisclient)) + return; + +$isCreate = (isset($options['mode']) && $options['mode'] == 'create'); +?> <tr><td colspan="2"><hr /> <div class="form-header" style="margin-bottom:0.5em"> <h3><?php echo Format::htmlchars($form->getTitle()); ?></h3> @@ -12,13 +15,11 @@ <?php // Form fields, each with corresponding errors follows. Fields marked // 'private' are not included in the output for clients - global $thisclient; foreach ($form->getFields() as $field) { - if (isset($options['mode']) && $options['mode'] == 'create') { + if ($isCreate) { if (!$field->isVisibleToUsers() && !$field->isRequiredForUsers()) continue; - } - elseif (!$field->isVisibleToUsers() && !$field->isEditableToUsers()) { + } elseif (!$field->isVisibleToUsers()) { continue; } ?> @@ -28,7 +29,8 @@ <label for="<?php echo $field->getFormName(); ?>"><span class="<?php if ($field->isRequiredForUsers()) echo 'required'; ?>"> <?php echo Format::htmlchars($field->getLocal('label')); ?> - <?php if ($field->isRequiredForUsers()) { ?> + <?php if ($field->isRequiredForUsers() && + ($field->isEditableToUsers() || $isCreate)) { ?> <span class="error">*</span> <?php } ?></span><?php @@ -40,12 +42,22 @@ <br/> <?php } - $field->render(array('client'=>true)); - ?></label><?php - foreach ($field->errors() as $e) { ?> - <div class="error"><?php echo $e; ?></div> - <?php } - $field->renderExtras(array('client'=>true)); + if ($field->isEditableToUsers() || $isCreate) { + $field->render(array('client'=>true)); + ?></label><?php + foreach ($field->errors() as $e) { ?> + <div class="error"><?php echo $e; ?></div> + <?php } + $field->renderExtras(array('client'=>true)); + } else { + $val = ''; + if ($field->value) + $val = $field->display($field->value); + elseif (($a=$field->getAnswer())) + $val = $a->display(); + + echo sprintf('%s </label>', $val); + } ?> </td> </tr> diff --git a/include/staff/templates/dynamic-form.tmpl.php b/include/staff/templates/dynamic-form.tmpl.php index ef18c8bd01c5a988f063d80caea823da0f857ca1..00abf34cbb93d08e8d73c1e36ed6beed2e3ef61a 100644 --- a/include/staff/templates/dynamic-form.tmpl.php +++ b/include/staff/templates/dynamic-form.tmpl.php @@ -1,6 +1,8 @@ <?php -// If the form was removed using the trashcan option, and there was some -// other validation error, don't render the deleted form the second time +global $thisstaff; + +$isCreate = (isset($options['mode']) && $options['mode'] == 'create'); + if (isset($options['entry']) && $options['mode'] == 'edit' && $_POST && ($_POST['forms'] && !in_array($options['entry']->getId(), $_POST['forms'])) @@ -42,8 +44,6 @@ if (isset($options['entry']) && $options['mode'] == 'edit') { ?> try { if (!$field->isEnabled()) continue; - if ($options['mode'] == 'edit' && !$field->isEditableToStaff()) - continue; } catch (Exception $e) { // Not connected to a DynamicFormField @@ -60,41 +60,52 @@ if (isset($options['entry']) && $options['mode'] == 'edit') { ?> <?php echo Format::htmlchars($field->getLocal('label')); ?>:</td> <td><div style="position:relative"><?php } - $field->render($options); ?> - <?php if (!$field->isBlockLevel() && $field->isRequiredForStaff()) { ?> - <span class="error">*</span> - <?php - } - if ($field->isStorable() && ($a = $field->getAnswer()) && $a->isDeleted()) { - ?><a class="action-button float-right danger overlay" title="Delete this data" - href="#delete-answer" - onclick="javascript:if (confirm('<?php echo __('You sure?'); ?>')) - $.ajax({ - url: 'ajax.php/form/answer/' - +$(this).data('entryId') + '/' + $(this).data('fieldId'), - type: 'delete', - success: $.proxy(function() { - $(this).closest('tr').fadeOut(); - }, this) - });" - data-field-id="<?php echo $field->getAnswer()->get('field_id'); - ?>" data-entry-id="<?php echo $field->getAnswer()->get('entry_id'); - ?>"> <i class="icon-trash"></i> </a></div><?php - } - if ($a && !$a->getValue() && $field->isRequiredForClose()) { -?><i class="icon-warning-sign help-tip warning" - data-title="<?php echo __('Required to close ticket'); ?>" - data-content="<?php echo __('Data is required in this field in order to close the related ticket'); ?>" -/></i><?php - } - if ($field->get('hint') && !$field->isBlockLevel()) { ?> - <br /><em style="color:gray;display:inline-block"><?php - echo Format::viewableImages($field->getLocal('hint')); ?></em> - <?php - } - foreach ($field->errors() as $e) { ?> - <div class="error"><?php echo Format::htmlchars($e); ?></div> - <?php } ?> + + if ($field->isEditableToStaff() || $isCreate) { + $field->render($options); ?> + <?php if (!$field->isBlockLevel() && $field->isRequiredForStaff()) { ?> + <span class="error">*</span> + <?php + } + if ($field->isStorable() && ($a = $field->getAnswer()) && $a->isDeleted()) { + ?><a class="action-button float-right danger overlay" title="Delete this data" + href="#delete-answer" + onclick="javascript:if (confirm('<?php echo __('You sure?'); ?>')) + $.ajax({ + url: 'ajax.php/form/answer/' + +$(this).data('entryId') + '/' + $(this).data('fieldId'), + type: 'delete', + success: $.proxy(function() { + $(this).closest('tr').fadeOut(); + }, this) + });" + data-field-id="<?php echo $field->getAnswer()->get('field_id'); + ?>" data-entry-id="<?php echo $field->getAnswer()->get('entry_id'); + ?>"> <i class="icon-trash"></i> </a></div><?php + } + if ($a && !$a->getValue() && $field->isRequiredForClose()) { + ?><i class="icon-warning-sign help-tip warning" + data-title="<?php echo __('Required to close ticket'); ?>" + data-content="<?php echo __('Data is required in this field in order to close the related ticket'); ?>" + /></i><?php + } + if ($field->get('hint') && !$field->isBlockLevel()) { ?> + <br /><em style="color:gray;display:inline-block"><?php + echo Format::viewableImages($field->getLocal('hint')); ?></em> + <?php + } + foreach ($field->errors() as $e) { ?> + <div class="error"><?php echo Format::htmlchars($e); ?></div> + <?php } + } else { + $val = ''; + if ($field->value) + $val = $field->display($field->value); + elseif (($a= $field->getAnswer())) + $val = $a->display(); + + echo $val; + }?> </div></td> </tr> <?php } diff --git a/include/staff/templates/user-lookup.tmpl.php b/include/staff/templates/user-lookup.tmpl.php index cfeeaddf65b5ce7640cef5158eac44a642e5c202..f46fd7c99e9e4689183998212220730b6485973f 100644 --- a/include/staff/templates/user-lookup.tmpl.php +++ b/include/staff/templates/user-lookup.tmpl.php @@ -83,8 +83,8 @@ if ($user) { ?> <form method="post" class="user" action="<?php echo $info['action'] ?: '#users/lookup/form'; ?>"> <table width="100%" class="fixed"> <?php - if(!$form) $form = UserForm::getInstance(); - $form->render(true, __('Create New User')); ?> + $form = $form ?: UserForm::getInstance(); + $form->render(true, __('Create New User'), array('mode' => 'create')); ?> </table> <hr> <p class="full-width"> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index 9fd5835b562c73b6ec5ce5e7e9f8b42b5cfc93f5..b1edfb999d04744e673705617233d0b32c3028e3 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -598,7 +598,9 @@ foreach (DynamicFormEntry::forTicket($ticket->getId()) as $form) { ))); $displayed = array(); foreach($answers as $a) { - $displayed[] = array($a->getLocal('label'), $a->display() ?: '<span class="faded">—' . __('Empty') . '— </span>', $a->getLocal('id'), ($a->getField() instanceof FileUploadField)); + if (!$a->getField()->isVisibleToStaff()) + continue; + $displayed[] = $a; } if (count($displayed) == 0) continue; @@ -609,13 +611,18 @@ foreach (DynamicFormEntry::forTicket($ticket->getId()) as $form) { </thead> <tbody> <?php - foreach ($displayed as $stuff) { - list($label, $v, $id, $isFile) = $stuff; + foreach ($displayed as $a) { + $id = $a->getLocal('id'); + $label = $a->getLocal('label'); + $v = $a->display() ?: '<span class="faded">—' . __('Empty') . '— </span>'; + $field = $a->getField(); + $isFile = ($field instanceof FileUploadField); ?> <tr> <td width="200"><?php echo Format::htmlchars($label); ?>:</td> <td> - <?php if ($role->hasPerm(Ticket::PERM_EDIT)) { + <?php if ($role->hasPerm(Ticket::PERM_EDIT) + && $field->isEditableToStaff()) { $isEmpty = strpos($v, '—'); if ($isFile && !$isEmpty) echo $v.'<br>'; ?> @@ -633,7 +640,8 @@ foreach (DynamicFormEntry::forTicket($ticket->getId()) as $form) { echo $v; ?> </a> - <?php } else { + <?php + } else { echo $v; } ?> </td> diff --git a/scp/js/scp.js b/scp/js/scp.js index c15d2330fdeeb6c8825ad5a68d11f82db0b3ba0b..025db554c60208d11e7754b1fe758a86f68478c7 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -835,8 +835,9 @@ $.confirm = function(message, title, options) { }; $.userLookup = function (url, cb) { - $.dialog(url, 201, function (xhr) { - var user = $.parseJSON(xhr.responseText); + $.dialog(url, 201, function (xhr, user) { + if ($.type(user) == 'string') + user = $.parseJSON(user); if (cb) return cb(user); }, { onshow: function() { $('#user-search').focus(); } @@ -844,8 +845,9 @@ $.userLookup = function (url, cb) { }; $.orgLookup = function (url, cb) { - $.dialog(url, 201, function (xhr) { - var org = $.parseJSON(xhr.responseText); + $.dialog(url, 201, function (xhr, org) { + if ($.type(org) == 'string') + org = $.parseJSON(user); if (cb) cb(org); }, { onshow: function() { $('#org-search').focus(); } diff --git a/tickets.php b/tickets.php index 560b16f3dc963008e05aa8c610607b82992fee95..93c7da3964d2460a8aadc2045b158c82cc959190 100644 --- a/tickets.php +++ b/tickets.php @@ -53,14 +53,17 @@ if ($_POST && is_object($ticket) && $ticket->getId()) { foreach ($forms as $form) { $form->filterFields(function($f) { return !$f->isStorable(); }); $form->setSource($_POST); - if (!$form->isValid()) + if (!$form->isValidForClient(true)) $errors = array_merge($errors, $form->errors()); } } if (!$errors) { - foreach ($forms as $f) { - $changes += $f->getChanges(); - $f->save(); + foreach ($forms as $form) { + $changes += $form->getChanges(); + $form->saveAnswers(function ($f) { + return $f->isVisibleToUsers() + && $f->isEditableToUsers(); }); + } if ($changes) { $user = User::lookup($thisclient->getId()); @@ -127,9 +130,9 @@ if($ticket && $ticket->checkUserAccess($thisclient)) { $inc = 'edit.inc.php'; if (!$forms) $forms=DynamicFormEntry::forTicket($ticket->getId()); // Auto add new fields to the entries - foreach ($forms as $f) { - $f->filterFields(function($f) { return !$f->isStorable(); }); - $f->addMissingFields(); + foreach ($forms as $form) { + $form->filterFields(function($f) { return !$f->isStorable(); }); + $form->addMissingFields(); } } else