diff --git a/account.php b/account.php index 97c8b5efdf6ee5812f5bf66979ba10b0915a4dcd..81f542eb2b46ebf8d953d196ddbb083aa3a54aac 100644 --- a/account.php +++ b/account.php @@ -58,7 +58,7 @@ elseif ($_POST) { $user_form->getField('email')->value = $thisclient->getEmail(); } - if (!$user_form->isValid(function($f) { return !$f->get('private'); })) + if (!$user_form->isValid(function($f) { return !$f->isVisibleToUsers(); })) $errors['err'] = __('Incomplete client information'); elseif (!$_POST['backend'] && !$_POST['passwd1']) $errors['passwd1'] = __('New password is required'); diff --git a/include/Spyc.php b/include/Spyc.php index 1c0fc31a8c90db69aeaefe4291590fe3c4aea96d..e92a4becea0016682299529c3fe290a44cdd21d2 100644 --- a/include/Spyc.php +++ b/include/Spyc.php @@ -617,6 +617,8 @@ class Spyc { if (is_numeric($value)) { if ($value === '0') return 0; + if (stripos($value, '0x') === 0) + $value = hexdec($value); if (rtrim ($value, 0) === $value) $value = (float)$value; return $value; diff --git a/include/ajax.forms.php b/include/ajax.forms.php index e53b91348a4d47b3a0b0bc44b001051f292f22d4..6c35f1bb2fe2055d220c89c583261a189223ddc0 100644 --- a/include/ajax.forms.php +++ b/include/ajax.forms.php @@ -48,7 +48,31 @@ class DynamicFormsAjaxAPI extends AjaxController { } function saveFieldConfiguration($field_id) { - $field = DynamicFormField::lookup($field_id); + if (!($field = DynamicFormField::lookup($field_id))) + Http::response(404, 'No such field'); + + $DFF = 'DynamicFormField'; + + // Capture flags which should remain unchanged + $p_mask = $DFF::MASK_MASK_ALL; + if ($field->isPrivacyForced()) { + $p_mask |= $DFF::FLAG_CLIENT_VIEW | $DFF::FLAG_AGENT_VIEW; + } + if ($field->isRequirementForced()) { + $p_mask |= $DFF::FLAG_CLIENT_REQUIRED | $DFF::FLAG_AGENT_REQUIRED; + } + if ($field->hasFlag($DFF::FLAG_MASK_DISABLE)) { + $p_mask |= $DFF::FLAG_ENABLED; + } + + // Capture current state of immutable flags + $preserve = $field->flags & $p_mask; + + // Set admin-configured flag states + $flags = array_reduce($_POST['flags'], + function($a, $b) { return $a | $b; }, 0); + $field->flags = $flags | $preserve; + if (!$field->setConfiguration()) { include STAFFINC_DIR . 'templates/dynamic-field-config.tmpl.php'; return; diff --git a/include/class.auth.php b/include/class.auth.php index fb055a5c379a706682a48d38b0e5a54e5622ab6d..e6fed10c5089badd4597d9ab220964b717964281 100644 --- a/include/class.auth.php +++ b/include/class.auth.php @@ -130,7 +130,7 @@ class ClientCreateRequest { if ($bk->supportsInteractiveAuthentication()) // User can only be authenticated against this backend $defaults['backend'] = $bk::$id; - if ($this_form->isValid(function($f) { return !$f->get('private'); }) + if ($this_form->isValid(function($f) { return !$f->isVisibleToUsers(); }) && ($U = User::fromVars($this_form->getClean())) && ($acct = ClientAccount::createForUser($U, $defaults)) // Confirm and save the account diff --git a/include/class.config.php b/include/class.config.php index d47d4144f3e8c084f502a5d9c00f78edabe01648..164171a920a964493fbd24ebe969f814709c65ee 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -156,7 +156,6 @@ class OsticketConfig extends Config { 'auto_claim_tickets'=> true, 'system_language' => 'en_US', 'default_storage_bk' => 'D', - 'allow_client_updates' => false, 'message_autoresponder_collabs' => true, 'add_email_collabs' => true, 'clients_only' => false, @@ -350,10 +349,6 @@ class OsticketConfig extends Config { return $this->get('enable_html_thread'); } - function allowClientUpdates() { - return $this->get('allow_client_updates'); - } - function getClientTimeout() { return $this->getClientSessionTimeout(); } diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php index 4bed6b6fdb00f4273dd06264ccdaf20bd9be1b54..3620cc1e87535dd3c3ead353676009d2554077d3 100644 --- a/include/class.dynamic_forms.php +++ b/include/class.dynamic_forms.php @@ -423,14 +423,27 @@ class DynamicFormField extends VerySimpleModel { var $_field; - const REQUIRE_NOBODY = 0; - const REQUIRE_EVERYONE = 1; - const REQUIRE_ENDUSER = 2; - const REQUIRE_AGENT = 3; + const FLAG_ENABLED = 0x0001; + const FLAG_STORABLE = 0x0002; + const FLAG_CLOSE_REQUIRED = 0x0004; - const VISIBLE_EVERYONE = 0; - const VISIBLE_AGENTONLY = 1; - const VISIBLE_ENDUSERONLY = 2; + const FLAG_MASK_CHANGE = 0x0010; + const FLAG_MASK_DELETE = 0x0020; + const FLAG_MASK_EDIT = 0x0040; + const FLAG_MASK_DISABLE = 0x0080; + const FLAG_MASK_REQUIRE = 0x10000; + const FLAG_MASK_VIEW = 0x20000; + const FLAG_MASK_NAME = 0x40000; + + const MASK_MASK_ALL = 0x700F0; + + const FLAG_CLIENT_VIEW = 0x0100; + const FLAG_CLIENT_EDIT = 0x0200; + const FLAG_CLIENT_REQUIRED = 0x0400; + + const FLAG_AGENT_VIEW = 0x1000; + const FLAG_AGENT_EDIT = 0x2000; + const FLAG_AGENT_REQUIRED = 0x4000; // Multiple inheritance -- delegate to FormField function __call($what, $args) { @@ -481,24 +494,61 @@ class DynamicFormField extends VerySimpleModel { } function isDeletable() { - return (($this->get('edit_mask') & 1) == 0); + return !$this->hasFlag(self::FLAG_MASK_DELETE); } function isNameForced() { - return $this->get('edit_mask') & 2; + return $this->hasFlag(self::FLAG_MASK_NAME); } function isPrivacyForced() { - return $this->get('edit_mask') & 4; + return $this->hasFlag(self::FLAG_MASK_VIEW); } function isRequirementForced() { - return $this->get('edit_mask') & 8; + return $this->hasFlag(self::FLAG_MASK_REQUIRE); } function isChangeable() { - return (($this->get('edit_mask') & 16) == 0); + return $this->hasFlag(self::FLAG_MASK_CHANGE); } function isEditable() { - return (($this->get('edit_mask') & 32) == 0); + return $this->hasFlag(self::FLAG_MASK_EDIT); + } + + function hasFlag($flag) { + return ($this->flags & $flag) != 0; + } + + function getVisibilityDescription() { + $F = $this->flags; + + if (!$this->hasFlag(self::FLAG_ENABLED)) + return __('Disabled'); + + $impl = $this->getImpl(); + + $hints = array(); + $VIEW = self::FLAG_CLIENT_VIEW | self::FLAG_AGENT_VIEW; + if (($F & $VIEW) == 0) { + $hints[] = __('Hidden'); + } + elseif (~$F & self::FLAG_CLIENT_VIEW) { + $hints[] = __('Internal'); + } + elseif (~$F & self::FLAG_AGENT_VIEW) { + $hints[] = __('For EndUsers Only'); + } + if ($impl->hasData()) { + if (~$F & (self::FLAG_CLIENT_REQUIRED | self::FLAG_AGENT_REQUIRED)) { + $hints[] = __('Optional'); + } + else { + $hints[] = __('Required'); + } + if (!($F & (self::FLAG_CLIENT_EDIT | self::FLAG_AGENT_EDIT))) { + $hints[] = __('Immutable'); + } + } + return implode(', ', $hints); } function getTranslateTag($subtag) { return _H(sprintf('field.%s.%s', $subtag, $this->id)); @@ -512,19 +562,28 @@ class DynamicFormField extends VerySimpleModel { function allRequirementModes() { return array( 'a' => array('desc' => __('Optional'), - 'private' => self::VISIBLE_EVERYONE, 'required' => self::REQUIRE_NOBODY), + 'flags' => self::FLAG_CLIENT_VIEW | self::FLAG_AGENT_VIEW + | self::FLAG_CLIENT_EDIT | self::FLAG_AGENT_EDIT), 'b' => array('desc' => __('Required'), - 'private' => self::VISIBLE_EVERYONE, 'required' => self::REQUIRE_EVERYONE), + 'flags' => self::FLAG_CLIENT_VIEW | self::FLAG_AGENT_VIEW + | self::FLAG_CLIENT_EDIT | self::FLAG_AGENT_EDIT + | self::FLAG_CLIENT_REQUIRED | self::FLAG_AGENT_REQUIRED), 'c' => array('desc' => __('Required for EndUsers'), - 'private' => self::VISIBLE_EVERYONE, 'required' => self::REQUIRE_ENDUSER), + 'flags' => self::FLAG_CLIENT_VIEW | self::FLAG_AGENT_VIEW + | self::FLAG_CLIENT_EDIT | self::FLAG_AGENT_EDIT + | self::FLAG_CLIENT_REQUIRED), 'd' => array('desc' => __('Required for Agents'), - 'private' => self::VISIBLE_EVERYONE, 'required' => self::REQUIRE_AGENT), + 'flags' => self::FLAG_CLIENT_VIEW | self::FLAG_AGENT_VIEW + | self::FLAG_CLIENT_EDIT | self::FLAG_AGENT_EDIT + | self::FLAG_AGENT_REQUIRED), 'e' => array('desc' => __('Internal, Optional'), - 'private' => self::VISIBLE_AGENTONLY, 'required' => self::REQUIRE_NOBODY), + 'flags' => self::FLAG_AGENT_VIEW | self::FLAG_AGENT_EDIT), 'f' => array('desc' => __('Internal, Required'), - 'private' => self::VISIBLE_AGENTONLY, 'required' => self::REQUIRE_EVERYONE), + 'flags' => self::FLAG_AGENT_VIEW | self::FLAG_AGENT_EDIT + | self::FLAG_AGENT_REQUIRED), 'g' => array('desc' => __('For EndUsers Only'), - 'private' => self::VISIBLE_ENDUSERONLY, 'required' => self::REQUIRE_ENDUSER), + 'flags' => self::FLAG_CLIENT_VIEW | self::FLAG_CLIENT_EDIT + | self::FLAG_CLIENT_REQUIRED), ); } @@ -533,7 +592,7 @@ class DynamicFormField extends VerySimpleModel { if ($this->isPrivacyForced()) { // Required to be internal foreach ($modes as $m=>$info) { - if ($info['private'] != $this->get('private')) + if ($info['flags'] & (self::FLAG_CLIENT_VIEW | self::FLAG_AGENT_VIEW)) unset($modes[$m]); } } @@ -541,47 +600,43 @@ class DynamicFormField extends VerySimpleModel { if ($this->isRequirementForced()) { // Required to be required foreach ($modes as $m=>$info) { - if ($info['required'] != $this->get('required')) + if ($info['flags'] & (self::FLAG_CLIENT_REQUIRED | self::FLAG_AGENT_REQUIRED)) unset($modes[$m]); } } return $modes; } - function getRequirementMode() { - foreach ($this->getAllRequirementModes() as $m=>$info) { - if ($this->get('private') == $info['private'] - && $this->get('required') == $info['required']) - return $m; - } - return false; - } - function setRequirementMode($mode) { $modes = $this->getAllRequirementModes(); if (!isset($modes[$mode])) return false; $info = $modes[$mode]; - $this->set('required', $info['required']); - $this->set('private', $info['private']); + $this->set('flags', $info['flags']); } function isRequiredForStaff() { - return in_array($this->get('required'), - array(self::REQUIRE_EVERYONE, self::REQUIRE_AGENT)); + return $this->hasFlag(self::FLAG_AGENT_REQUIRED); } function isRequiredForUsers() { - return in_array($this->get('required'), - array(self::REQUIRE_EVERYONE, self::REQUIRE_ENDUSER)); + return $this->hasFlag(self::FLAG_CLIENT_REQUIRED); + } + function isEditableToStaff() { + return $this->hasFlag(self::FLAG_ENABLED) + && $this->hasFlag(self::FLAG_AGENT_EDIT); } function isVisibleToStaff() { - return in_array($this->get('private'), - array(self::VISIBLE_EVERYONE, self::VISIBLE_AGENTONLY)); + return $this->hasFlag(self::FLAG_ENABLED) + && $this->hasFlag(self::FLAG_AGENT_VIEW); + } + function isEditableToUsers() { + return $this->hasFlag(self::FLAG_ENABLED) + && $this->hasFlag(self::FLAG_CLIENT_EDIT); } function isVisibleToUsers() { - return in_array($this->get('private'), - array(self::VISIBLE_EVERYONE, self::VISIBLE_ENDUSERONLY)); + return $this->hasFlag(self::FLAG_ENABLED) + && $this->hasFlag(self::FLAG_CLIENT_VIEW); } /** diff --git a/include/class.forms.php b/include/class.forms.php index 7cebfb42fabed8cb04bd9b7f6b8376d1e6c4ef49..3410477d781b8d56b95883e426a0e5b9f41521f4 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -1448,6 +1448,11 @@ class ThreadEntryField extends FormField { if ($cfg->getAllowedFileTypes()) $fileupload_config['extensions']->set('default', $cfg->getAllowedFileTypes()); + foreach ($fileupload_config as $C) { + $C->set('visibility', new VisibilityConstraint(new Q(array( + 'attachments__eq'=>true, + )), VisibilityConstraint::HIDDEN)); + } return array( 'attachments' => new BooleanField(array( 'label'=>__('Enable Attachments'), diff --git a/include/class.ticket.php b/include/class.ticket.php index 7caac30d9b936543bcf5df2ff6ed503cc01fc9c9..33400acbd1d1093cee4855b1827d0918cb821a36 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -791,6 +791,15 @@ class Ticket { return $this->recipients; } + function hasClientEditableFields() { + $forms = DynamicFormEntry::forTicket($this->getId()); + foreach ($forms as $form) { + foreach ($form->getFields() as $field) { + if ($field->isEditableToUsers()) + return true; + } + } + } function addCollaborator($user, $vars, &$errors) { @@ -2221,7 +2230,7 @@ class Ticket { if (!in_array($form->getId(), $vars['forms'])) continue; $form->setSource($_POST); - if (!$form->isValid()) + if (!$form->isValidForStaff()) $errors = array_merge($errors, $form->errors()); } @@ -2456,10 +2465,9 @@ class Ticket { case 'staff': // Required 'Contact Information' fields aren't required // when staff open tickets - return $type != 'user' - || in_array($f->get('name'), array('name','email')); + return $f->isVisibleToStaff(); case 'web': - return !$f->get('private'); + return $f->isVisibleToUsers(); default: return true; } @@ -2772,6 +2780,13 @@ class Ticket { /* -------------------- POST CREATE ------------------------ */ // Save the (common) dynamic form + // Ensure we have a subject + $subject = $form->getAnswer('subject'); + if ($subject && !$subject->getValue()) { + if ($topic) { + $form->setAnswer('subject', $topic->getFullName()); + } + } $form->setTicketId($id); $form->save(); diff --git a/include/client/templates/dynamic-form.tmpl.php b/include/client/templates/dynamic-form.tmpl.php index 66b957a49100562520e1bb11a765a27d13120d1d..0672b2263829dea6aa804a6345c2c2489ff84c61 100644 --- a/include/client/templates/dynamic-form.tmpl.php +++ b/include/client/templates/dynamic-form.tmpl.php @@ -5,7 +5,7 @@ ?> <tr><td colspan="2"><hr /> <div class="form-header" style="margin-bottom:0.5em"> - <?php print ($form instanceof DynamicFormEntry) + <?php print ($form instanceof DynamicFormEntry) ? $form->getForm()->getMedia() : $form->getMedia(); ?> <h3><?php echo Format::htmlchars($form->getTitle()); ?></h3> <em><?php echo Format::htmlchars($form->getInstructions()); ?></em> @@ -16,19 +16,18 @@ // 'private' are not included in the output for clients global $thisclient; foreach ($form->getFields() as $field) { - if (!$field->isVisibleToUsers()) + if (!$field->isEditableToUsers()) continue; ?> <tr> <td colspan="2" style="padding-top:8px;"> <?php if (!$field->isBlockLevel()) { ?> <label for="<?php echo $field->getFormName(); ?>"><span class="<?php - if ($field->get('required')) echo 'required'; ?>"> + if ($field->isRequiredForUsers()) echo 'required'; ?>"> <?php echo Format::htmlchars($field->getLocal('label')); ?> - <?php if ($field->get('required')) { ?> + <?php if ($field->isRequiredForUsers()) { ?> <span class="error">*</span> - <?php - } + <?php } ?></span><?php if ($field->get('hint')) { ?> <br /><em style="color:gray;display:inline-block"><?php @@ -41,8 +40,7 @@ $field->render('client'); ?></label><?php foreach ($field->errors() as $e) { ?> - <br /> - <font class="error"><?php echo $e; ?></font> + <div class="error"><?php echo $e; ?></div> <?php } $field->renderExtras('client'); ?> diff --git a/include/client/view.inc.php b/include/client/view.inc.php index cd0b2ccd3dd859e1de52acc8df6cf4249c08e57b..6fb76a9d969208436d36b1f072133a24fd368e9c 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -32,12 +32,12 @@ if ($thisclient && $thisclient->isGuest() <td colspan="2" width="100%"> <h1> <?php echo sprintf(__('Ticket #%s'), $ticket->getNumber()); ?> - <a href="tickets.php?id=<?php echo $ticket->getId(); ?>" title="Reload"><span class="Icon refresh"> </span></a> -<?php if ($cfg->allowClientUpdates() + <a href="tickets.php?id=<?php echo $ticket->getId(); ?>" title="<?php echo __('Reload'); ?>"><span class="Icon refresh"> </span></a> +<?php if ($ticket->hasClientEditableFields() // Only ticket owners can edit the ticket details (and other forms) && $thisclient->getId() == $ticket->getUserId()) { ?> <a class="action-button pull-right" href="tickets.php?a=edit&id=<?php - echo $ticket->getId(); ?>"><i class="icon-edit"></i> Edit</a> + echo $ticket->getId(); ?>"><i class="icon-edit"></i> <?php echo __('Edit'); ?></a> <?php } ?> </h1> </td> @@ -88,7 +88,7 @@ foreach (DynamicFormEntry::forTicket($ticket->getId()) as $idx=>$form) { <?php foreach ($answers as $answer) { if (in_array($answer->getField()->get('name'), array('name', 'email', 'subject'))) continue; - elseif ($answer->getField()->get('private')) + elseif (!$answer->getField()->isVisibleToUsers()) continue; ?> <tr> diff --git a/include/i18n/en_US/form.yaml b/include/i18n/en_US/form.yaml index d8759c8fc57500485f266f28221a88f194ce2e33..85c8fc00ab553dbe1b842e174a166e44314e92f0 100644 --- a/include/i18n/en_US/form.yaml +++ b/include/i18n/en_US/form.yaml @@ -16,10 +16,15 @@ # will be used to retrieve the data from the field. # hint: Help text shown with the field # flags: Bit mask for settings & options -# edit_mask: Mask out edits to the field (1=>delete, 2=>change name, -# 4=>privacy setting, 8=>requirement setting) -# private: True if the field should be hidden from the client -# required: True if entry for the field is required +# # From class DynamicFormField +# const FLAG_MASK_CHANGE = 0x0010; # Type cannot change +# const FLAG_MASK_DELETE = 0x0020; # Cannot be deleted +# const FLAG_MASK_EDIT = 0x0040; # Data cannot be edited +# const FLAG_MASK_DISABLE = 0x0080; # Field cannot be disabled +# const FLAG_MASK_REQUIRE = 0x10000; # Requirement cannot be changed +# const FLAG_MASK_VIEW = 0x20000; # View settings cannot be changed +# const FLAG_MASK_NAME = 0x40000; # Name cannot be changed +# # configuration: Field-specific configuration # size: (text) width of the field # length: (text) maximum size of the data in the field @@ -35,10 +40,8 @@ - type: text # notrans name: email # notrans label: Email Address - required: true sort: 1 - flags: 3 - edit_mask: 15 + flags: 0x777A3 configuration: size: 40 length: 64 @@ -46,25 +49,21 @@ - type: text # notrans name: name # notrans label: Full Name - required: true sort: 2 - flags: 3 - edit_mask: 15 + flags: 0x777A3 configuration: size: 40 length: 64 - type: phone # notrans name: phone # notrans label: Phone Number - required: false sort: 3 - flags: 1 + flags: 0x3301 - type: memo # notrans name: notes label: Internal Notes - required: false - private: true sort: 4 + flags: 0x3001 configuration: rows: 4 cols: 40 @@ -82,10 +81,8 @@ type: text # notrans name: subject # notrans label: Issue Summary - required: true - edit_mask: 15 sort: 1 - flags: 1 + flags: 0x77721 configuration: size: 40 length: 50 @@ -94,18 +91,13 @@ name: message # notrans label: Issue Details hint: Details on the reason(s) for opening the ticket. - required: true - edit_mask: 15 sort: 2 - flags: 3 + flags: 0x75523 - id: 22 type: priority # notrans name: priority # notrans label: Priority Level - required: false - private: true - edit_mask: 3 - sort: 3 + sort: 0x430A3 flags: 1 - type: C # notrans title: Company Information @@ -115,10 +107,8 @@ - type: text # notrans name: name # notrans label: Company Name - required: true sort: 1 - flags: 1 - edit_mask: 3 + flags: 0x471A1 configuration: size: 40 length: 64 @@ -126,24 +116,22 @@ name: website # notrans label: Website sort: 2 - flags: 1 + flags: 0x3101 configuration: size: 40 length: 64 - type: phone # notrans name: phone # notrans label: Phone Number - required: false sort: 3 - flags: 1 + flags: 0x3101 configuration: ext: false - type: memo # notrans name: address label: Address - required: false sort: 4 - flags: 1 + flags: 0x3101 configuration: rows: 2 cols: 40 @@ -157,19 +145,16 @@ - type: text # notrans name: name # notrans label: Name - required: true sort: 1 - flags: 3 - edit_mask: 15 + flags: 0x777A3 configuration: size: 40 length: 64 - type: memo name: address label: Address - required: false sort: 2 - flags: 1 + flags: 0x3301 configuration: rows: 2 cols: 40 @@ -178,24 +163,21 @@ - type: phone name: phone label: Phone - required: false sort: 3 - flags: 1 + flags: 0x3301 - type: text name: website label: Website - required: false sort: 4 - flags: 1 + flags: 0x3301 configuration: size: 40 length: 0 - type: memo # notrans name: notes label: Internal Notes - required: false sort: 5 - flags: 1 + flags: 0x3001 configuration: rows: 4 cols: 40 diff --git a/include/i18n/en_US/list.yaml b/include/i18n/en_US/list.yaml index 613ca4a2f83db4a46048c70069a9569c95791a86..2dbd2e7a4145fddd34ca064bf50bc7da19a49341 100644 --- a/include/i18n/en_US/list.yaml +++ b/include/i18n/en_US/list.yaml @@ -37,17 +37,15 @@ - type: state # notrans name: state # notrans label: State - required: true sort: 1 - edit_mask: 63 + flags: 0x770F1 configuration: prompt: State of a ticket - type: memo # notrans name: description # notrans label: Description - required: false sort: 3 - edit_mask: 15 + flags: 0x73021 configuration: rows: 2 cols: 40 diff --git a/include/staff/dynamic-form.inc.php b/include/staff/dynamic-form.inc.php index b79a4320d6f190d529cd0e258ad937e3b362581c..bf68e752f874f376c1183e4dde7971b85232565b 100644 --- a/include/staff/dynamic-form.inc.php +++ b/include/staff/dynamic-form.inc.php @@ -83,17 +83,13 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); $uform = UserForm::objects()->all(); $ftypes = FormField::allTypes(); foreach ($uform[0]->getFields() as $f) { - if ($f->get('private')) continue; + if (!$f->isVisibleToUsers()) continue; ?> <tr> <td></td> <td><?php echo $f->get('label'); ?></td> <td><?php $t=FormField::getFieldType($f->get('type')); echo __($t[0]); ?></td> - <td><?php - $rmode = $f->getRequirementMode(); - $modes = $f->getAllRequirementModes(); - echo $modes[$rmode]['desc']; - ?></td> + <td><?php echo $f->getVisibilityDescription(); ?></td> <td><?php echo $f->get('name'); ?></td> <td><input type="checkbox" disabled="disabled"/></td></tr> @@ -127,7 +123,6 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); $id = $f->get('id'); $deletable = !$f->isDeletable() ? 'disabled="disabled"' : ''; $force_name = $f->isNameForced() ? 'disabled="disabled"' : ''; - $rmode = $f->getRequirementMode(); $fi = $f->getImpl(); $ferrors = $f->errors(); ?> <tr> @@ -162,12 +157,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); "><i class="icon-edit"></i> <?php echo __('Config'); ?></a> <?php } ?></td> <td> - <select name="visibility-<?php echo $id; ?>"> -<?php foreach ($f->getAllRequirementModes() as $m=>$I) { ?> - <option value="<?php echo $m; ?>" <?php if ($rmode == $m) - echo 'selected="selected"'; ?>><?php echo $I['desc']; ?></option> -<?php } ?> - <select> + <?php echo $f->getVisibilityDescription(); ?> </td> <td> <input type="text" size="20" name="name-<?php echo $id; ?>" diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php index d64c52ed12a4f7e4148598e75d292a93430cbe59..603f43dfa3a7695772a79db0d5fe8688f9e76bd6 100644 --- a/include/staff/settings-tickets.inc.php +++ b/include/staff/settings-tickets.inc.php @@ -200,14 +200,6 @@ if(!($maxfileuploads=ini_get('max_file_uploads'))) <i class="help-tip icon-question-sign" href="#enable_html_ticket_thread"></i> </td> </tr> - <tr> - <td><?php echo __('Allow Client Updates'); ?>:</td> - <td> - <input type="checkbox" name="allow_client_updates" <?php - echo $config['allow_client_updates']?'checked="checked"':''; ?>> - <?php echo __('Allow clients to update ticket details via the web portal'); ?> - </td> - </tr> <tr> <th colspan="2"> <em><b><?php echo __('Attachments');?></b>: <?php echo __('Size and maximum uploads setting mainly apply to web tickets.');?></em> diff --git a/include/staff/templates/dynamic-field-config.tmpl.php b/include/staff/templates/dynamic-field-config.tmpl.php index d9db95352e1c1de6fcaf655d2f3bfb94e0b6d458..65932bf656f9960ed7f80c540316646dd979d881 100644 --- a/include/staff/templates/dynamic-field-config.tmpl.php +++ b/include/staff/templates/dynamic-field-config.tmpl.php @@ -3,6 +3,123 @@ <hr/> <form method="post" action="#form/field-config/<?php echo $field->get('id'); ?>"> +<ul class="tabs"> + <li><a href="#config" class="active"><i class="icon-cogs"></i> Field Setup</a></li> + <li><a href="#visibility"><i class="icon-beaker"></i> Settings</a></li> +</ul> + +<div class="tab_content" id="visibility" style="display:none"> + <div> + <div class="span4"> + <div style="margin-bottom:5px"><strong>Enabled</strong> + <i class="help-tip icon-question-sign" + data-title="Enabled" + data-content="This field can be disabled which will remove it + from the form for new entries, but will preserve the data on all + current entries."></i> + </div> + </div> + <div class="span6"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_ENABLED; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_ENABLED)) echo 'checked="checked"'; + if ($field->hasFlag(DynamicFormField::FLAG_MASK_DISABLE)) echo ' disabled="disabled"'; + ?>> Enabled<br/> + </div> + <hr class="faded"/> + + <div class="span4"> + <div style="margin-bottom:5px"><strong>Visible</strong> + <i class="help-tip icon-question-sign" + data-title="Visible" + data-content="Making fields <em>visible</em> allows agents and + endusers to view and create information in this field."></i> + </div> + </div> + <div class="span3"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_CLIENT_VIEW; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_CLIENT_VIEW)) echo 'checked="checked"'; + if ($field->isPrivacyForced()) echo ' disabled="disabled"'; + ?>> For Clients<br/> + </div> + <div class="span3"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_AGENT_VIEW; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_AGENT_VIEW)) echo 'checked="checked"'; + if ($field->isPrivacyForced()) echo ' disabled="disabled"'; + ?>> For Agents<br/> + </div> + +<?php if ($field->getImpl()->hasData()) { ?> + <hr class="faded"/> + + <div class="span4"> + <div style="margin-bottom:5px"><strong>Required</strong> + <i class="help-tip icon-question-sign" + data-title="Required" + data-content="New entries cannot be created unless all + <em>required</em> fields have valid data."></i> + </div> + </div> + <div class="span3"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_CLIENT_REQUIRED; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_CLIENT_REQUIRED)) echo 'checked="checked"'; + if ($field->isRequirementForced()) echo ' disabled="disabled"'; + ?>> For Clients<br/> + </div> + <div class="span3"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_AGENT_REQUIRED; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_AGENT_REQUIRED)) echo 'checked="checked"'; + if ($field->isRequirementForced()) echo ' disabled="disabled"'; + ?>> For Agents<br/> + </div> + <hr class="faded"/> + + <div class="span4"> + <div style="margin-bottom:5px"><strong>Editable</strong> + <i class="help-tip icon-question-sign" + data-content="Fields marked editable allow agents and endusers to update the + content of this field after the form entry has been created." + data-title="Editable"></i> + </div> + </div> + + <div class="span3"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_CLIENT_EDIT; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_CLIENT_EDIT)) echo 'checked="checked"'; + ?>> For Clients<br/> + </div> + <div class="span3"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_AGENT_EDIT; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_AGENT_EDIT)) echo 'checked="checked"'; + ?>> For Agents<br/> + </div> + <hr class="faded"/> + + <div class="span4"> + <div style="margin-bottom:5px"><strong>Data Integrity</strong> + <i class="help-tip icon-question-sign" + data-title="Required to close a ticket" + data-content="Optionally, this field can prevent closing a + ticket until it has valid data."></i> + </div> + </div> + <div class="span6"> + <input type="checkbox" name="flags[]" value="<?php + echo DynamicFormField::FLAG_CLOSE_REQUIRED; ?>" <?php + if ($field->hasFlag(DynamicFormField::FLAG_CLOSE_REQUIRED)) echo 'checked="checked"'; + ?>> Required to close a ticket<br/> + </div> +<?php } ?> + </div> +</div> + +<div class="tab_content" id="config"> <?php echo csrf_token(); $form = $field->getConfigurationForm(); @@ -50,6 +167,7 @@ echo Format::htmlchars($field->get('hint')); ?></textarea> </div> </div> +</div> <hr> <p class="full-width"> <span class="buttons pull-left"> @@ -62,7 +180,41 @@ </p> </form> <div class="clear"></div> + <script type="text/javascript"> // Make translatable fields translatable $('input[data-translate-tag], textarea[data-translate-tag]').translatable(); </script> + +<style type="text/css"> +.span3 { + width: 22.25%; + margin: 0 1%; + display: inline-block; + vertical-align: top; +} +.span4 { + width: 30.25%; + margin: 0 1%; + display: inline-block; + vertical-align: top; +} +.span6 { + width: 47.25%; + margin: 0 1%; + display: inline-block; + vertical-align: top; +} +.span12 { + width: 97%; + margin: 0 1%; + display: inline-block; + vertical-align: top; +} +.dialog input, .dialog select { + margin: 2px; +} +hr.faded { + opacity: 0.3; +} +</style> diff --git a/include/staff/templates/dynamic-form.tmpl.php b/include/staff/templates/dynamic-form.tmpl.php index f0db379b8459e9735babff88c969e0a4ad249277..4efb94a218fc3d789693511306f2bee093020fbb 100644 --- a/include/staff/templates/dynamic-form.tmpl.php +++ b/include/staff/templates/dynamic-form.tmpl.php @@ -38,7 +38,7 @@ if (isset($options['entry']) && $options['mode'] == 'edit') { ?> } foreach ($form->getFields() as $field) { try { - if (!$field->isVisibleToStaff()) + if (!$field->isEditableToStaff()) continue; } catch (Exception $e) { @@ -50,14 +50,14 @@ if (isset($options['entry']) && $options['mode'] == 'edit') { ?> <?php } else { ?> - <td class="multi-line <?php if ($field->get('required')) echo 'required'; + <td class="multi-line <?php if ($field->isRequiredForStaff()) echo 'required'; ?>" style="min-width:120px;" <?php if ($options['width']) echo "width=\"{$options['width']}\""; ?>> <?php echo Format::htmlchars($field->getLocal('label')); ?>:</td> <td><div style="position:relative"><?php } $field->render(); ?> - <?php if (!$field->isBlockLevel() && $field->get('required')) { ?> + <?php if (!$field->isBlockLevel() && $field->isRequiredForStaff()) { ?> <span class="error">*</span> <?php } diff --git a/tickets.php b/tickets.php index 5b15b0015870db4509d07bc3e7f8c7a3ea5b8a1f..2161b67b2658326dcc29a388286a96be077b7e59 100644 --- a/tickets.php +++ b/tickets.php @@ -47,8 +47,6 @@ if($_POST && is_object($ticket) && $ticket->getId()): if(!$ticket->checkUserAccess($thisclient) //double check perm again! || $thisclient->getId() != $ticket->getUserId()) $errors['err']=__('Access Denied. Possibly invalid ticket ID'); - elseif (!$cfg || !$cfg->allowClientUpdates()) - $errors['err']=__('Access Denied. Client updates are currently disabled'); else { $forms=DynamicFormEntry::forTicket($ticket->getId()); foreach ($forms as $form) { @@ -107,7 +105,7 @@ endif; $nav->setActiveNav('tickets'); if($ticket && $ticket->checkUserAccess($thisclient)) { if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'edit' - && $cfg->allowClientUpdates()) { + && $ticket->hasClientEditableFields()) { $inc = 'edit.inc.php'; if (!$forms) $forms=DynamicFormEntry::forTicket($ticket->getId()); // Auto add new fields to the entries