diff --git a/bootstrap.php b/bootstrap.php index 405ce00c3fb0916e86b4af602724bce8992f6ab5..5f8ba40fea09216d84fffed8dcd2098e09cd384c 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -335,9 +335,9 @@ define('CLI_DIR', INCLUDE_DIR.'cli/'); /*############## Do NOT monkey with anything else beyond this point UNLESS you really know what you are doing ##############*/ #Current version && schema signature (Changes from version to version) -define('THIS_VERSION','1.8-git'); //Shown on admin panel define('GIT_VERSION','$git'); define('MAJOR_VERSION', '1.12'); +define('THIS_VERSION', MAJOR_VERSION.'-git'); //Shown on admin panel //Path separator if(!defined('PATH_SEPARATOR')){ if(strpos($_ENV['OS'],'Win')!==false || !strcasecmp(substr(PHP_OS, 0, 3),'WIN')) diff --git a/include/ajax.orgs.php b/include/ajax.orgs.php index d3ffc8b9dec2b994ae95efd133104a4860d308dc..83a4e85f77112aff25f386f63b0dc7ace0a8f802 100644 --- a/include/ajax.orgs.php +++ b/include/ajax.orgs.php @@ -24,8 +24,8 @@ class OrgsAjaxAPI extends AjaxController { if(!isset($_REQUEST['q'])) { Http::response(400, 'Query argument is required'); - } - + } + if (!$_REQUEST['q']) return $this->json_encode(array()); @@ -92,7 +92,10 @@ class OrgsAjaxAPI extends AjaxController { Http::response(404, 'Unknown organization'); $errors = array(); - if($org->update($_POST, $errors)) + if ($profile) { + if ($org->updateProfile($_POST, $errors)) + Http::response(201, $org->to_json(), 'application/json'); + } elseif ($org->update($_POST, $errors)) Http::response(201, $org->to_json(), 'application/json'); $forms = $org->getForms(); diff --git a/include/ajax.staff.php b/include/ajax.staff.php index 5356e9ccf6c52efb3f550da04c6cb3fb3ced1d75..6b6197dd58c45c47d3ff8f55d091b786a3cf84dc 100644 --- a/include/ajax.staff.php +++ b/include/ajax.staff.php @@ -145,7 +145,7 @@ class StaffAjaxAPI extends AjaxController { $form = new ResetAgentPermissionsForm($_POST); if (@is_array($_GET['ids'])) { - $perms = new RolePermission(); + $perms = new RolePermission(null); $selected = Staff::objects()->filter(array('staff_id__in' => $_GET['ids'])); foreach ($selected as $staff) // XXX: This maybe should be intersection rather than union diff --git a/include/class.dept.php b/include/class.dept.php index 8654e3e75f8203ba9af68d213c54de0a25d46e2c..7c92000a942e1c3b69b03e16c33178c0f3d58e9b 100644 --- a/include/class.dept.php +++ b/include/class.dept.php @@ -71,6 +71,7 @@ implements TemplateVariable, Searchable { const FLAG_ACTIVE = 0x0004; const FLAG_ARCHIVED = 0x0008; const FLAG_ASSIGN_PRIMARY_ONLY = 0x0010; + const FLAG_DISABLE_REOPEN_AUTO_ASSIGN = 0x0020; function asVar() { return $this->getName(); @@ -464,6 +465,10 @@ implements TemplateVariable, Searchable { return $this->flags & self::FLAG_DISABLE_AUTO_CLAIM; } + function disableReopenAutoAssign() { + return $this->flags & self::FLAG_DISABLE_REOPEN_AUTO_ASSIGN; + } + function isGroupMembershipEnabled() { return $this->group_membership; } @@ -477,7 +482,7 @@ implements TemplateVariable, Searchable { $ht['disable_auto_claim'] = $this->disableAutoClaim(); $ht['status'] = $this->getStatus(); $ht['assignment_flag'] = $this->getAssignmentFlag(); - + $ht['disable_reopen_auto_assign'] = $this->disableReopenAutoAssign(); return $ht; } @@ -809,6 +814,7 @@ implements TemplateVariable, Searchable { $this->setFlag(self::FLAG_ASSIGN_MEMBERS_ONLY, isset($vars['assign_members_only'])); $this->setFlag(self::FLAG_DISABLE_AUTO_CLAIM, isset($vars['disable_auto_claim'])); + $this->setFlag(self::FLAG_DISABLE_REOPEN_AUTO_ASSIGN, isset($vars['disable_reopen_auto_assign'])); $filter_actions = FilterAction::objects()->filter(array('type' => 'dept', 'configuration' => '{"dept_id":'. $this->getId().'}')); if ($filter_actions && $vars['status'] == 'active') diff --git a/include/class.file.php b/include/class.file.php index 0334d57e7d11360f7e2526c13d95d985602aa6eb..204b7945fe4051d02b988578b89d309e7d99807f 100644 --- a/include/class.file.php +++ b/include/class.file.php @@ -261,7 +261,10 @@ class AttachmentFile extends VerySimpleModel { } function download($name=false, $disposition=false, $expires=false) { - $disposition = ($disposition && strcasecmp($disposition, 'inline') == 0 + $thisstaff = StaffAuthenticationBackend::getUser(); + $inline = ($thisstaff ? ($thisstaff->getImageAttachmentView() === 'inline') : false); + $disposition = ((($disposition && strcasecmp($disposition, 'inline') == 0) + || $inline) && strpos($this->getType(), 'image/') !== false) ? 'inline' : 'attachment'; $bk = $this->open(); diff --git a/include/class.organization.php b/include/class.organization.php index 179aa2c151ad898a0f279dfb2761663d5a8fd6a0..6a6fbcdb0c183d9833f861f98fa1a7b80887f943 100644 --- a/include/class.organization.php +++ b/include/class.organization.php @@ -372,22 +372,7 @@ implements TemplateVariable, Searchable { return true; } - function update($vars, &$errors) { - - $valid = true; - $forms = $this->getForms($vars); - foreach ($forms as $entry) { - if (!$entry->isValid()) - $valid = false; - if ($entry->getDynamicForm()->get('type') == 'O' - && ($f = $entry->getField('name')) - && $f->getClean() - && ($o=Organization::lookup(array('name'=>$f->getClean()))) - && $o->id != $this->getId()) { - $valid = false; - $f->addError(__('Organization with the same name already exists')); - } - } + function updateProfile($vars, &$errors) { if ($vars['domain']) { foreach (explode(',', $vars['domain']) as $d) { @@ -411,20 +396,13 @@ implements TemplateVariable, Searchable { } } - if (!$valid || $errors) - return false; + // Attempt to valid & update dynamic data even on errors + if (!$this->update($vars, $errors)) + $errors['error'] = __('Unable to update organization form'); - foreach ($this->getDynamicData() as $entry) { - if ($entry->getDynamicForm()->get('type') == 'O' - && ($name = $entry->getField('name')) - ) { - $this->name = $name->getClean(); - $this->save(); - } - $entry->setSource($vars); - if ($entry->save()) - $this->updated = SqlFunction::NOW(); - } + + if ($errors) + return false; // Set flags foreach (array( @@ -467,6 +445,43 @@ implements TemplateVariable, Searchable { return $this->save(); } + + function update($vars, &$errors) { + + $valid = true; + $forms = $this->getForms($vars); + foreach ($forms as $entry) { + if (!$entry->isValid()) + $valid = false; + if ($entry->getDynamicForm()->get('type') == 'O' + && ($f = $entry->getField('name')) + && $f->getClean() + && ($o=Organization::lookup(array('name'=>$f->getClean()))) + && $o->id != $this->getId()) { + $valid = false; + $f->addError(__('Organization with the same name already exists')); + } + } + + if (!$valid || $errors) + return false; + + // Save dynamic data. + foreach ($this->getDynamicData() as $entry) { + if ($entry->getDynamicForm()->get('type') == 'O' + && ($name = $entry->getField('name')) + ) { + $this->name = $name->getClean(); + $this->save(); + } + $entry->setSource($vars); + if ($entry->save()) + $this->updated = SqlFunction::NOW(); + } + + return true; + } + function delete() { if (!parent::delete()) return false; diff --git a/include/class.staff.php b/include/class.staff.php index f3ec54ae2462bd8317c65a6e05d86e0f95e9cb0a..14acef885afdea70994569765d9809ba0d248c29 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -93,6 +93,7 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable { 'thread_view_order' => '', 'default_ticket_queue_id' => 0, 'reply_redirect' => 'Ticket', + 'img_att_view' => 'download', )); $this->_config = $_config->getInfo(); } @@ -353,6 +354,10 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable { return $this->reply_redirect; } + function getImageAttachmentView() { + return $this->img_att_view; + } + function forcePasswdChange() { return $this->change_passwd; } @@ -769,6 +774,7 @@ implements AuthenticatedUser, EmailContact, TemplateVariable, Searchable { 'thread_view_order' => $vars['thread_view_order'], 'default_ticket_queue_id' => $vars['default_ticket_queue_id'], 'reply_redirect' => ($vars['reply_redirect'] == 'Queue') ? 'Queue' : 'Ticket', + 'img_att_view' => ($vars['img_att_view'] == 'inline') ? 'inline' : 'download', ) ); $this->_config = $_config->getInfo(); diff --git a/include/class.ticket.php b/include/class.ticket.php index 593df7d8a1a5893dda9bef3c797c7e16f2e74591..9309e1f9a2d4f5c25eba09bf7a6a508e71f22e3c 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -1705,8 +1705,8 @@ implements RestrictedAccess, Threadable, Searchable { // to unassigned pool. $dept = $this->getDept(); $staff = $this->getStaff() ?: $this->getLastRespondent(); - $autoclaim = ($cfg->autoClaimTickets() && !$dept->disableAutoClaim()); - if ($autoclaim + $autoassign = (!$dept->disableReopenAutoAssign()); + if ($autoassign && $staff // Is agent on vacation ? && $staff->isAvailable() diff --git a/include/cli/modules/deploy.php b/include/cli/modules/deploy.php index eb76a165f0f9784d8b9ad1c7debf4edb735861d3..f9eb912af33b15591d53f0a9d62e8b6bb5e4fb00 100644 --- a/include/cli/modules/deploy.php +++ b/include/cli/modules/deploy.php @@ -122,7 +122,7 @@ class Deployment extends Unpacker { } if (!$version) - $version = exec('git describe'); + $version = preg_replace('/^v(\d{1}\.\d{2}).*$/', '$1-git', exec('git describe')); if (!$short || !$version) return false; diff --git a/include/i18n/en_US/help/tips/settings.ticket.yaml b/include/i18n/en_US/help/tips/settings.ticket.yaml index a736db8e0cc29871f04d5936c296c605bde495d2..f273a8a4682a338ee24566d19258c7bd7f6014a9 100644 --- a/include/i18n/en_US/help/tips/settings.ticket.yaml +++ b/include/i18n/en_US/help/tips/settings.ticket.yaml @@ -98,7 +98,8 @@ claim_tickets: content: > Enable this to auto-assign unassigned tickets to the responding Agent. <br><br> - Reopened tickets are always assigned to the last respondent. + Reopened tickets are always assigned to the last respondent unless auto + assign on reopen is disabled on the Department level. collaborator_ticket_visibility: title: Collaborator Tickets Visibility @@ -135,4 +136,3 @@ ticket_attachment_settings: class="doc-desc-title">issue details</span> field. These settings are used for all new tickets and new messages regardless of the source channel (web portal, email, api, etc.). - diff --git a/include/i18n/en_US/help/tips/staff.department.yaml b/include/i18n/en_US/help/tips/staff.department.yaml index 96e348f6470924028c4e5c19540c8f94f875ddfc..d10f78185378fd65c038c639ec27f1e117ed4ffe 100644 --- a/include/i18n/en_US/help/tips/staff.department.yaml +++ b/include/i18n/en_US/help/tips/staff.department.yaml @@ -89,6 +89,14 @@ disable_auto_claim: <br><br> Agents can still manually claim unassigned tickets +disable_reopen_auto_assign: + title: Disable Auto Assign on Reopen + content: > + Check this to <strong>disable</strong> auto-assignment of reopened tickets for + this department. + <br><br> + Otherwise, the Ticket will be auto assigned to the last responding Agent + auto_response_settings: title: Autoresponder Settings content: > diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php index b743aa5f62add15ab1e2e9cf42e937e04ccacdce..e8ebbba223f3ce4aaada4238f61be92a2e3bf14a 100644 --- a/include/staff/department.inc.php +++ b/include/staff/department.inc.php @@ -192,6 +192,21 @@ $info = Format::htmlchars(($errors && $_POST) ? $_POST : $info); </td> </tr> + <tr> + <td><?php echo __('Reopen Auto Assignment'); ?>:</td> + <td> + <label> + <input type="checkbox" name="disable_reopen_auto_assign" <?php echo + $info['disable_reopen_auto_assign'] ? 'checked="checked"' : ''; ?>> + <?php echo sprintf('<strong>%s</strong> %s', + __('Disable'), + __('auto assign on reopen')); ?> + </label> + <i class="help-tip icon-question-sign" + href="#disable_reopen_auto_assign"></i> + </td> + </tr> + <tr> <th colspan="2"> <em><strong><?php echo __('Outgoing Email Settings'); ?></strong>:</em> diff --git a/include/staff/profile.inc.php b/include/staff/profile.inc.php index 8e72ffc43c6638b3a52505f20679a80d16a061d0..a23c76b2ec3df13e38b8a465da6b47c223c6e4ee 100644 --- a/include/staff/profile.inc.php +++ b/include/staff/profile.inc.php @@ -317,6 +317,23 @@ if ($avatar->isChangeable()) { ?> <div class="error"><?php echo $errors['reply_redirect']; ?></div> </td> </tr> + <tr> + <td><?php echo __('Image Attachment View'); ?>: + <div class="faded"><?php echo __('Open image attachments in new tab or directly download. (CTRL + Right Click)');?></div> + </td> + <td> + <select name="img_att_view"> + <?php + $options=array('download'=>__('Download'),'inline'=>__('Inline')); + foreach($options as $key=>$opt) { + echo sprintf('<option value="%s" %s>%s</option>', + $key,($staff->img_att_view==$key)?'selected="selected"':'',$opt); + } + ?> + </select> + <div class="error"><?php echo $errors['img_att_view']; ?></div> + </td> + </tr> </tbody> <tbody> <tr class="header">