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/ajax.tickets.php b/include/ajax.tickets.php index d5d12bea93f519e3b443038fbcdda61f35615566..d8fccf5dc451aa81a673e56627f00e7c82e25854 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -609,7 +609,7 @@ class TicketsAjaxAPI extends AjaxController { $state = strtolower($status->getState()); - if (!$errors && $ticket->setStatus($status, $_REQUEST['comments'])) { + if (!$errors && $ticket->setStatus($status, $_REQUEST['comments'], $errors)) { if ($state == 'deleted') { $msg = sprintf('%s %s', @@ -723,13 +723,15 @@ class TicketsAjaxAPI extends AjaxController { if (($ticket=Ticket::lookup($tid)) && $ticket->getStatusId() != $status->getId() && $ticket->checkStaffAccess($thisstaff) - && $ticket->setStatus($status, $comments)) + && $ticket->setStatus($status, $comments, $errors)) $i++; } - if (!$i) - $errors['err'] = sprintf(__('Unable to change status for %s'), + if (!$i) { + $errors['err'] = $errors['err'] + ?: sprintf(__('Unable to change status for %s'), _N('the selected ticket', 'any of the selected tickets', $count)); + } else { // Assume success if ($i==$count) { 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 1ff552bd0d80edd5d56242312e1cc8ff4dab00e2..b582110b0100c933334ed03592e3d2c8f6afddeb 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_EXT_STORED = 0x0002; // Value stored outside of form_entry_value + 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,46 @@ 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 isRequiredForClose() { + return $this->hasFlag(self::FLAG_CLOSE_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); } /** @@ -689,10 +747,12 @@ class DynamicFormEntry extends VerySimpleModel { return $ans; return null; } + function setAnswer($name, $value, $id=false) { foreach ($this->getAnswers() as $ans) { - if ($ans->getField()->get('name') == $name) { - $ans->getField()->reset(); + $f = $ans->getField(); + if ($f->isStorable() && $f->get('name') == $name) { + $f->reset(); $ans->set('value', $value); if ($id !== false) $ans->set('value_id', $id); @@ -907,18 +967,8 @@ class DynamicFormEntry extends VerySimpleModel { $this->_fields[] = $fImpl; $this->_form = null; - // Omit fields without data - // For user entries, the name and email fields should not be - // saved with the rest of the data - if ($this->object_type == 'U' - && in_array($field->get('name'), array('name','email'))) - continue; - - if ($this->object_type == 'O' - && in_array($field->get('name'), array('name'))) - continue; - - if (!$field->hasData()) + // Omit fields without data and non-storable fields. + if (!$field->hasData() || !$field->isStorable()) continue; $a->save(); @@ -937,15 +987,10 @@ class DynamicFormEntry extends VerySimpleModel { $this->set('updated', new SqlFunction('NOW')); parent::save(); foreach ($this->getFields() as $field) { - $a = $field->getAnswer(); - if ($this->object_type == 'U' - && in_array($field->get('name'), array('name','email'))) - continue; - - if ($this->object_type == 'O' - && in_array($field->get('name'), array('name'))) + if (!$field->isStorable()) continue; + $a = $field->getAnswer(); // Set the entry ID here so that $field->getClean() can use the // entry-id if necessary $a->set('entry_id', $this->get('id')); diff --git a/include/class.forms.php b/include/class.forms.php index e744f172cc41cd4b3cd073f659da8b2c1b888540..c3d61ea25454a428252841834fbaa5c14ba1d822 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -397,6 +397,18 @@ class FormField { return (($this->get('edit_mask') & 32) == 0); } + /** + * isStorable + * + * Indicate if this field data is storable locally (default).Some field's data + * might beed to be stored elsewhere for optimization reasons at the + * application level. + * + */ + + function isStorable() { + return (($this->get('flags') & DynamicFormField::FLAG_EXT_STORED) == 0); + } /** * parse @@ -1436,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..5bdec7646de19b257870924cdfdcdf90b8bddb6f 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -791,6 +791,35 @@ 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 getMissingRequiredFields() { + $returnArray = array(); + $forms=DynamicFormEntry::forTicket($this->getId()); + foreach ($forms as $form) { + foreach ($form->getFields() as $field) { + if ($field->isRequiredForClose()) { + if (!($field->answer->get('value'))) { + array_push($returnArray, $field->get('label')); + } + } + } + } + return $returnArray; + } + + function getMissingRequiredField() { + $fields = $this->getMissingRequiredFields(); + return $fields[0]; + } function addCollaborator($user, $vars, &$errors) { @@ -948,7 +977,7 @@ class Ticket { } //Status helper. - function setStatus($status, $comments='') { + function setStatus($status, $comments='', &$errors=array()) { global $thisstaff; if ($status && is_numeric($status)) @@ -970,6 +999,12 @@ class Ticket { $ecb = null; switch($status->getState()) { case 'closed': + if ($this->getMissingRequiredFields()) { + $errors['err'] = sprintf(__( + 'This ticket is missing data on %s one or more required fields %s and cannot be closed'), + '', ''); + return false; + } $sql.=', closed=NOW(), lastupdate=NOW(), duedate=NULL '; if ($thisstaff) $sql.=', staff_id='.db_input($thisstaff->getId()); @@ -2221,7 +2256,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 +2491,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 +2806,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 b5bde9db9af53ae3189a77080db5085e649184cf..85c8fc00ab553dbe1b842e174a166e44314e92f0 100644 --- a/include/i18n/en_US/form.yaml +++ b/include/i18n/en_US/form.yaml @@ -15,10 +15,16 @@ # useful for page and email templates, where %{ ticket.<name> } # will be used to retrieve the data from the field. # hint: Help text shown with the field -# 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 +# flags: Bit mask for settings & options +# # 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 @@ -34,9 +40,8 @@ - type: text # notrans name: email # notrans label: Email Address - required: true sort: 1 - edit_mask: 15 + flags: 0x777A3 configuration: size: 40 length: 64 @@ -44,23 +49,21 @@ - type: text # notrans name: name # notrans label: Full Name - required: true sort: 2 - edit_mask: 15 + flags: 0x777A3 configuration: size: 40 length: 64 - type: phone # notrans name: phone # notrans label: Phone Number - required: false sort: 3 + flags: 0x3301 - type: memo # notrans name: notes label: Internal Notes - required: false - private: true sort: 4 + flags: 0x3001 configuration: rows: 4 cols: 40 @@ -78,9 +81,8 @@ type: text # notrans name: subject # notrans label: Issue Summary - required: true - edit_mask: 15 sort: 1 + flags: 0x77721 configuration: size: 40 length: 50 @@ -89,17 +91,14 @@ name: message # notrans label: Issue Details hint: Details on the reason(s) for opening the ticket. - required: true - edit_mask: 15 sort: 2 + 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 instructions: Details available in email templates @@ -108,9 +107,8 @@ - type: text # notrans name: name # notrans label: Company Name - required: true sort: 1 - edit_mask: 3 + flags: 0x471A1 configuration: size: 40 length: 64 @@ -118,21 +116,22 @@ name: website # notrans label: Website sort: 2 + flags: 0x3101 configuration: size: 40 length: 64 - type: phone # notrans name: phone # notrans label: Phone Number - required: false sort: 3 + flags: 0x3101 configuration: ext: false - type: memo # notrans name: address label: Address - required: false sort: 4 + flags: 0x3101 configuration: rows: 2 cols: 40 @@ -146,17 +145,16 @@ - type: text # notrans name: name # notrans label: Name - required: true sort: 1 - edit_mask: 15 + flags: 0x777A3 configuration: size: 40 length: 64 - type: memo name: address label: Address - required: false sort: 2 + flags: 0x3301 configuration: rows: 2 cols: 40 @@ -165,21 +163,21 @@ - type: phone name: phone label: Phone - required: false sort: 3 + flags: 0x3301 - type: text name: website label: Website - required: false sort: 4 + flags: 0x3301 configuration: size: 40 length: 0 - type: memo # notrans name: notes label: Internal Notes - required: false sort: 5 + 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..8d725dece67078da3e8fbba1b7578fc84e32d4ab 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() || $field->isRequiredForClose()) 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 } @@ -77,6 +77,12 @@ if (isset($options['entry']) && $options['mode'] == 'edit') { ?> ?>" data-entry-id="<?php echo $field->getAnswer()->get('entry_id'); ?>"> <i class="icon-trash"></i> </a></div><?php } + if (!$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::htmlchars($field->getLocal('hint')); ?></em> diff --git a/include/staff/templates/status-options.tmpl.php b/include/staff/templates/status-options.tmpl.php index cdcaa395bec9a424a61f6bf62f9b4a29f0ef58b2..c82696e6ff2e052dd84294afb6586233ae7fa5b8 100644 --- a/include/staff/templates/status-options.tmpl.php +++ b/include/staff/templates/status-options.tmpl.php @@ -12,6 +12,23 @@ $actions= array( 'action' => 'reopen' ), ); + +$states = array('open'); +if ($thisstaff->canCloseTickets() && (!$ticket || !$ticket->getMissingRequiredFields())) + $states = array_merge($states, array('closed')); + +$statusId = $ticket ? $ticket->getStatusId() : 0; +$nextStatuses = array(); +foreach (TicketStatusList::getStatuses( + array('states' => $states)) as $status) { + if (!isset($actions[$status->getState()]) + || $statusId == $status->getId()) + continue; + $nextStatuses[] = $status; +} + +if (!$nextStatuses) + return; ?> <span @@ -26,18 +43,7 @@ $actions= array( <div id="action-dropdown-statuses" class="action-dropdown anchor-right"> <ul> - <?php - $states = array('open'); - if ($thisstaff->canCloseTickets()) - $states = array_merge($states, array('closed')); - - $statusId = $ticket ? $ticket->getStatusId() : 0; - foreach (TicketStatusList::getStatuses( - array('states' => $states))->all() as $status) { - if (!isset($actions[$status->getState()]) - || $statusId == $status->getId()) - continue; - ?> +<?php foreach ($nextStatuses as $status) { ?> <li> <a class="no-pjax <?php echo $ticket? 'ticket-action' : 'tickets-action'; ?>" diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index 74f819e0d70663c78b1c3d74d4d09e3ae03b1730..207d573c5da4c312a1f7ba9448167cfb2a7dec72 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -605,15 +605,23 @@ print $response_form->getField('attachments')->render(); </td> </tr> <tr> - <td width="120"> + <td width="120" style="vertical-align:top"> <label><strong><?php echo __('Ticket Status');?>:</strong></label> </td> <td> + <?php + if ($outstanding = $ticket->getMissingRequiredFields()) { ?> + <div class="warning-banner"><?php echo sprintf(__( + 'This ticket is missing data on %s one or more required fields %s and cannot be closed'), + "<a href=\"tickets.php?id={$ticket->getId()}&a=edit\">", + '</a>' + ); ?></div> +<?php } ?> <select name="reply_status_id"> <?php $statusId = $info['reply_status_id'] ?: $ticket->getStatusId(); $states = array('open'); - if ($thisstaff->canCloseTickets()) + if ($thisstaff->canCloseTickets() && !$outstanding) $states = array_merge($states, array('closed')); foreach (TicketStatusList::getStatuses( diff --git a/include/upgrader/streams/core.sig b/include/upgrader/streams/core.sig index 595363a70fc0d9b2206f9b3054e4aca2deaa66e6..776ffc839a61c0b88c0387008deb5ea18c453bce 100644 --- a/include/upgrader/streams/core.sig +++ b/include/upgrader/streams/core.sig @@ -1 +1 @@ -7c218d81e84b304c1436326c26ace09d +1ee831c854fe9f35115a3e672916bb91 diff --git a/include/upgrader/streams/core/b26f29a6-7c218d81.cleanup.sql b/include/upgrader/streams/core/b26f29a6-1ee831c8.cleanup.sql similarity index 86% rename from include/upgrader/streams/core/b26f29a6-7c218d81.cleanup.sql rename to include/upgrader/streams/core/b26f29a6-1ee831c8.cleanup.sql index 38a11ec1a9dff14d79cdfb20ef5c229b8cafd6c0..f56a5cb2c0d24deac939bc08b185cbdcc53119d1 100644 --- a/include/upgrader/streams/core/b26f29a6-7c218d81.cleanup.sql +++ b/include/upgrader/streams/core/b26f29a6-1ee831c8.cleanup.sql @@ -1,6 +1,6 @@ /** - * @signature d7480e1c31a1f20d6954ecbb342722d3 - * @version v1.9.5 + * @signature 1ee831c854fe9f35115a3e672916bb91 + * @version v1.9.6 * @title Make editable content translatable * * This patch adds support for translatable administratively editable diff --git a/include/upgrader/streams/core/b26f29a6-7c218d81.patch.sql b/include/upgrader/streams/core/b26f29a6-1ee831c8.patch.sql similarity index 78% rename from include/upgrader/streams/core/b26f29a6-7c218d81.patch.sql rename to include/upgrader/streams/core/b26f29a6-1ee831c8.patch.sql index 4d98136aa645bd97aaf5f32a775cb7e378ddbafe..52d6856b725f2ec369144174172e330bceb9f2b0 100644 --- a/include/upgrader/streams/core/b26f29a6-7c218d81.patch.sql +++ b/include/upgrader/streams/core/b26f29a6-1ee831c8.patch.sql @@ -1,5 +1,5 @@ /** - * @signature 7c218d81e84b304c1436326c26ace09d + * @signature 1ee831c854fe9f35115a3e672916bb91 * @version v1.9.6 * @title Make editable content translatable and add queues * @@ -172,7 +172,41 @@ CREATE TABLE `%TABLE_PREFIX%queue` ( primary key (`id`) ) DEFAULT CHARSET=utf8; +-- Add flags field to form field +ALTER TABLE `%TABLE_PREFIX%form_field` + ADD `flags` INT UNSIGNED NOT NULL DEFAULT '1' AFTER `form_id`; + +-- Flag field stored in the system elsewhere as nonstorable locally. +UPDATE `%TABLE_PREFIX%form_field` A1 JOIN `%TABLE_PREFIX%form` A2 ON(A2.id=A1.form_id) + SET A1.`flags` = 3 + WHERE A2.`type` = 'U' AND A1.`name` IN('name','email'); + +UPDATE `%TABLE_PREFIX%form_field` A1 JOIN `%TABLE_PREFIX%form` A2 ON(A2.id=A1.form_id) + SET A1.`flags`=3 + WHERE A2.`type`='O' AND A1.`name` IN('name'); + +set @client_edit = ( + select value from `%TABLE_PREFIX%config` where `key` = 'allow_client_updates'); + +-- Transfer previous visibility and requirement settings to new flag field +UPDATE `%TABLE_PREFIX%form_field` SET `flags` = `flags` | + CASE WHEN `private` = 0 and @client_edit = 1 THEN CONV(3300, 16, 10) + WHEN `private` = 0 and @client_edit = 0 THEN CONV(3100, 16, 10) + WHEN `private` = 1 THEN CONV(3000, 16, 10) + WHEN `private` = 2 and @client_edit = 1 THEN CONV(300, 16, 10) END + WHEN `private` = 2 and @client_edit = 0 THEN CONV(100, 16, 10) END + | CASE WHEN `required` = 0 THEN 0 + WHEN `required` = 1 THEN CONV(4400, 16, 10) + WHEN `required` = 2 THEN CONV(400, 16, 10) + WHEN `required` = 3 THEN CONV(4000, 16, 10) END + | IF(`edit_mask` & 1, CONV(20, 16, 10), 0) + | IF(`edit_mask` & 2, CONV(40000, 16, 10), 0) + | IF(`edit_mask` & 4, CONV(10000, 16, 10), 0) + | IF(`edit_mask` & 8, CONV(20000, 16, 10), 0) + | IF(`edit_mask` & 16, CONV(10, 16, 10), 0) + | IF(`edit_mask` & 32, CONV(40, 16, 10), 0); + -- Finished with patch UPDATE `%TABLE_PREFIX%config` - SET `value` = '7c218d81e84b304c1436326c26ace09d' + SET `value` = '1ee831c854fe9f35115a3e672916bb91' WHERE `key` = 'schema_signature' AND `namespace` = 'core'; diff --git a/include/upgrader/streams/core/b26f29a6-7c218d81.task.php b/include/upgrader/streams/core/b26f29a6-1ee831c8.task.php similarity index 100% rename from include/upgrader/streams/core/b26f29a6-7c218d81.task.php rename to include/upgrader/streams/core/b26f29a6-1ee831c8.task.php diff --git a/scp/css/scp.css b/scp/css/scp.css index 6bbdcc8abcd61d9e67e4f5fbf7a19ec4aff505a0..b97e1cc2bcfdc37b4a840095165b790d043311dc 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -2018,7 +2018,8 @@ button a:hover { font-style: italic; } -.form_table tr:hover i.help-tip { +.form_table tr:hover i.help-tip, +.form_table tr i.help-tip.warning { opacity: 1; color: #ffc20f; } diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql index b10118f2fb5dc49d4f42b74df3e0e5b01b147bc4..f32ff6d74962ad72ed72886ef9fcefb145d1e039 100644 --- a/setup/inc/streams/core/install-mysql.sql +++ b/setup/inc/streams/core/install-mysql.sql @@ -127,6 +127,7 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%form_field`; CREATE TABLE `%TABLE_PREFIX%form_field` ( `id` int(11) unsigned NOT NULL auto_increment, `form_id` int(11) unsigned NOT NULL, + `flags` int(10) unsigned DEFAULT 1, `type` varchar(255) NOT NULL DEFAULT 'text', `label` varchar(255) NOT NULL, `required` tinyint(1) NOT NULL DEFAULT 0, 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