diff --git a/file.php b/file.php index 994b77a0c2256a0218a27ffebb01b1c7d77a344b..00193f7a0b4b810964d9388a2a9a893f00406907 100644 --- a/file.php +++ b/file.php @@ -28,10 +28,11 @@ if (!$_GET['key'] // Get the object type the file is attached to $type = ''; +$attachment = null; if ($_GET['id'] - && ($a=$file->attachments->findFirst(array( + && ($attachment=$file->attachments->findFirst(array( 'id' => $_GET['id'])))) - $type = $a->type; + $type = $attachment->type; // Enforce security settings if enabled. if ($cfg->isAuthRequiredForFiles() @@ -62,7 +63,9 @@ if ($file->verifySignature($_GET['signature'], $_GET['expires'])) { return $file->display($s); // Download the file.. - $file->download(@$_GET['disposition'] ?: false, $_GET['expires']); + $filename = $attachment ? $attachment->name : $file->getName(); + $disposition = @$_GET['disposition'] ?: false; + $file->download($filename, $disposition, @$_GET['expires']); } catch (Exception $ex) { Http::response(500, 'Unable to find that file: '.$ex->getMessage()); diff --git a/include/ajax.tasks.php b/include/ajax.tasks.php index 88b11bee010075c07b8293d260ec09f284569891..cd85cf613cbf696280ae79182946d6c9e6b46fea 100644 --- a/include/ajax.tasks.php +++ b/include/ajax.tasks.php @@ -84,8 +84,10 @@ class TasksAjaxAPI extends AjaxController { function add($tid=0, $vars=array()) { global $thisstaff; - if ($tid) - $originalTask = Task::lookup($tid); + if ($tid) { + $vars = array_merge($_SESSION[':form-data'], $vars); + $originalTask = Task::lookup($tid); + } else unset($_SESSION[':form-data']); @@ -111,7 +113,7 @@ class TasksAjaxAPI extends AjaxController { if ($desc && $desc->isAttachmentsEnabled() && ($attachments=$desc->getWidget()->getAttachments())) - $vars['cannedattachments'] = $attachments->getClean(); + $vars['files'] = $attachments->getFiles(); $vars['staffId'] = $thisstaff->getId(); $vars['poster'] = $thisstaff; $vars['ip_address'] = $_SERVER['REMOTE_ADDR']; @@ -809,9 +811,9 @@ class TasksAjaxAPI extends AjaxController { switch ($_POST['a']) { case 'postnote': $vars = $_POST; - $attachments = $note_form->getField('attachments')->getClean(); - $vars['cannedattachments'] = array_merge( - $vars['cannedattachments'] ?: array(), $attachments); + $attachments = $note_form->getField('attachments')->getFiles(); + $vars['files'] = array_merge( + $vars['files'] ?: array(), $attachments); if(($note=$task->postNote($vars, $errors, $thisstaff))) { $msg=__('Note posted successfully'); // Clear attachment list diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index 4f5e7a62bcc55939dd2c788b86ee880a4fe37489..2864efda74a09e4c5ceed50e699f15edbff6f5ef 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -1382,7 +1382,7 @@ function refer($tid, $target=null) { && ($f=$iform->getField('duedate'))) { $f->configure('max', Misc::db2gmtime($ticket->getEstDueDate())); } - + $vars = array_merge($_SESSION[':form-data'], $vars); if ($_POST) { Draft::deleteForNamespace( @@ -1408,7 +1408,7 @@ function refer($tid, $target=null) { if ($desc && $desc->isAttachmentsEnabled() && ($attachments=$desc->getWidget()->getAttachments())) - $vars['cannedattachments'] = $attachments->getClean(); + $vars['files'] = $attachments->getFiles(); $vars['staffId'] = $thisstaff->getId(); $vars['poster'] = $thisstaff; $vars['ip_address'] = $_SERVER['REMOTE_ADDR']; @@ -1490,9 +1490,9 @@ function refer($tid, $target=null) { $vars = $_POST; switch ($_POST['a']) { case 'postnote': - $attachments = $note_attachments_form->getField('attachments')->getClean(); - $vars['cannedattachments'] = array_merge( - $vars['cannedattachments'] ?: array(), $attachments); + $attachments = $note_attachments_form->getField('attachments')->getFiles(); + $vars['files'] = array_merge( + $vars['files'] ?: array(), $attachments); if (($note=$task->postNote($vars, $errors, $thisstaff))) { $msg=__('Note posted successfully'); // Clear attachment list @@ -1506,9 +1506,9 @@ function refer($tid, $target=null) { } break; case 'postreply': - $attachments = $reply_attachments_form->getField('attachments')->getClean(); - $vars['cannedattachments'] = array_merge( - $vars['cannedattachments'] ?: array(), $attachments); + $attachments = $reply_attachments_form->getField('attachments')->getFiles(); + $vars['files'] = array_merge( + $vars['files'] ?: array(), $attachments); if (($response=$task->postReply($vars, $errors))) { $msg=__('Update posted successfully'); // Clear attachment list diff --git a/include/class.attachment.php b/include/class.attachment.php index bcda6d08af5d757c01b691b78a29b28f03def623..bb5e8e292f11aa0342f82299f7d2b5c1bec04dd8 100644 --- a/include/class.attachment.php +++ b/include/class.attachment.php @@ -60,6 +60,10 @@ class Attachment extends VerySimpleModel { return $this->name ?: $this->file->name; } + function getName() { + return $this->getFilename(); + } + function getHashtable() { return $this->ht; } @@ -108,16 +112,15 @@ extends InstrumentedList { */ function keepOnlyFileIds($ids, $inline=false, $lang=false) { if (!$ids) $ids = array(); - $new = array_flip($ids); foreach ($this as $A) { - if (!isset($new[$A->file_id]) && $A->lang == $lang && $A->inline == $inline) + if (!isset($ids[$A->file_id]) && $A->lang == $lang && $A->inline == $inline) // Not in the $ids list, delete $this->remove($A); - unset($new[$A->file_id]); + unset($ids[$A->file_id]); } $attachments = array(); // Format $new for upload() with new name - foreach ($new as $id=>$name) { + foreach ($ids as $id=>$name) { $attachments[] = array( 'id' => $id, 'name' => $name @@ -134,7 +137,7 @@ extends InstrumentedList { foreach ($files as $file) { if (is_numeric($file)) $fileId = $file; - elseif (is_array($file) && isset($file['id'])) + elseif (is_array($file) && isset($file['id']) && $file['id']) $fileId = $file['id']; elseif (isset($file['tmp_name']) && ($F = AttachmentFile::upload($file))) $fileId = $F->getId(); diff --git a/include/class.canned.php b/include/class.canned.php index 21cd9aa6367f2b4ec81959d1790177fbb751ad65..388420c5f541a7667f7d3c33a020df5000a68b36 100644 --- a/include/class.canned.php +++ b/include/class.canned.php @@ -138,7 +138,7 @@ extends VerySimpleModel { $resp['files'] = array(); foreach ($this->getAttachedFiles(!$html) as $file) { - $_SESSION[':cannedFiles'][$file->id] = 1; + $_SESSION[':cannedFiles'][$file->id] = $file->name; $resp['files'][] = array( 'id' => $file->id, 'name' => $file->name, diff --git a/include/class.file.php b/include/class.file.php index d880840861b09065a34cd275ebb726773d82e105..e61b5afe76516fcecfd880359bb6193c13164b4e 100644 --- a/include/class.file.php +++ b/include/class.file.php @@ -248,7 +248,7 @@ class AttachmentFile extends VerySimpleModel { return hash_hmac('sha1', implode("\n", $pieces), SECRET_SALT); } - function download($disposition=false, $expires=false) { + function download($name=false, $disposition=false, $expires=false) { $disposition = $disposition ?: 'inline'; $bk = $this->open(); if ($bk->sendRedirectUrl($disposition)) @@ -258,7 +258,7 @@ class AttachmentFile extends VerySimpleModel { $type = $this->getType() ?: 'application/octet-stream'; if (isset($_REQUEST['overridetype'])) $type = $_REQUEST['overridetype']; - Http::download($this->getName(), $type, null, 'inline'); + Http::download($name ?: $this->getName(), $type, null, 'inline'); header('Content-Length: '.$this->getSize()); $this->sendData(false); exit(); diff --git a/include/class.filter.php b/include/class.filter.php index 311bfb91dddc179ed9725cb4a1dccdc18a016ef0..5066eb002df1e940167bc5abdcea2cbae8b7bc1d 100755 --- a/include/class.filter.php +++ b/include/class.filter.php @@ -137,8 +137,10 @@ extends VerySimpleModel { if ($val) $this->flags |= $flag; else - $this->flags &= ~$flag; - $this->save(); + $this->ht['flags'] &= ~$flag; + $vars['rules']= $this->getRules(); + $this->ht['pass'] = true; + $this->update($this->ht, $errors); } function stopOnMatch() { @@ -490,6 +492,10 @@ extends VerySimpleModel { } function validate_actions($vars, &$errors) { + //allow the save if it is to set a filter flag + if ($vars['pass']) + return true; + if (!is_array(@$vars['actions'])) return; foreach ($vars['actions'] as $sort=>$v) { @@ -517,26 +523,30 @@ extends VerySimpleModel { } } } - switch ($action->ht['type']) { - case 'dept': - $dept = Dept::lookup($config['dept_id']); - if (!$dept || !$dept->isActive()) { - $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Department'); - } - break; - case 'topic': - $topic = Topic::lookup($config['topic_id']); - if (!$topic || !$topic->isActive()) { - $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Help Topic'); - } - break; - default: - foreach ($config as $key => $value) { - if (!$value) { - $errors['err'] = sprintf(__('Unable to save: Please insert a value for %s'), ucfirst($action->ht['type'])); - } + + // do not throw an error if we are deleting an action + if (substr($v, 0, 1) != 'D') { + switch ($action->ht['type']) { + case 'dept': + $dept = Dept::lookup($config['dept_id']); + if (!$dept || !$dept->isActive()) { + $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Department'); + } + break; + case 'topic': + $topic = Topic::lookup($config['topic_id']); + if (!$topic || !$topic->isActive()) { + $errors['err'] = sprintf(__('Unable to save: Please choose an active %s'), 'Help Topic'); + } + break; + default: + foreach ($config as $key => $value) { + if (!$value) { + $errors['err'] = sprintf(__('Unable to save: Please insert a value for %s'), ucfirst($action->ht['type'])); + } + } + break; } - break; } } return count($errors) == 0; diff --git a/include/class.forms.php b/include/class.forms.php index b2c04d6c514e610d9692728dd5c7a66e172d8dc1..4fb4de4609802681c71b57d2c9b8009d66d0aa77 100644 --- a/include/class.forms.php +++ b/include/class.forms.php @@ -1974,10 +1974,25 @@ class DatetimeField extends FormField { 'w' => _N('week', 'weeks', $count), 'm' => _N('month', 'months', $count), ); - return $i ? $intervals[$i] : $intervals; } + static function periods($period='') { + $periods = array( + 'td' => __('Today'), + 'yd' => __('Yesterday'), + 'tw' => __('This Week'), + 'tm' => __('This Month'), + 'tq' => __('This Quater'), + 'ty' => __('This Year'), + 'lw' => __('Last Week'), + 'lm' => __('Last Month'), + 'lq' => __('Last Quater'), + 'ly' => __('Last Year'), + ); + return $period ? $periods[$period] : $periods; + } + // Get php DatateTime object of the field - null if value is empty function getDateTime($value=null) { return Format::parseDateTime($value ?: $this->value); @@ -2190,6 +2205,7 @@ class DatetimeField extends FormField { 'before' => __('before'), 'after' => __('after'), 'between' => __('between'), + 'period' => __('period'), 'ndaysago' => __('in the last n days'), 'ndays' => __('in the next n days'), 'future' => __('in the future'), @@ -2239,6 +2255,9 @@ class DatetimeField extends FormField { 'right' => new DatetimeField(), ), )), + 'period' => array('ChoiceField', array( + 'choices' => self::periods(), + )), 'ndaysago' => array('InlineformField', array('form'=>$nday_form())), 'ndays' => array('InlineformField', array('form'=>$nday_form())), 'distfut' => array('InlineformField', array('form'=>$nday_form())), @@ -2247,6 +2266,8 @@ class DatetimeField extends FormField { } function getSearchQ($method, $value, $name=false) { + global $cfg; + static $intervals = array( 'm' => 'MONTH', 'w' => 'WEEK', @@ -2257,10 +2278,9 @@ class DatetimeField extends FormField { $name = $name ?: $this->get('name'); $now = SqlFunction::NOW(); $config = $this->getConfiguration(); - if (is_int($value)) $value = DateTime::createFromFormat('U', !$config['gmt'] ? Misc::gmtime($value) : $value) ?: $value; - elseif (is_string($value)) + elseif (is_string($value) && strlen($value) > 2) $value = Format::parseDateTime($value) ?: $value; switch ($method) { @@ -2322,6 +2342,27 @@ class DatetimeField extends FormField { return new Q(array( "{$name}__gte" => $now->plus($interval), )); + case 'period': + // Get the period range boundaries - timezone doesn't matter + $period = Misc::date_range($value, Misc::gmtime('now')); + $tz = new DateTimeZone($cfg->getTimezone()); + // Get datetime boundaries in user's effective timezone + $tz = new DateTimeZone($cfg->getTimezone()); + $start = new DateTime($period->start->format('Y-m-d H:i:s'), + $tz); + $end = new DateTime($period->end->format('Y-m-d H:i:s'), $tz); + // Convert boundaries to db time + $dbtz = new DateTimeZone($cfg->getDbTimezone()); + $start->setTimezone($dbtz); + $end->setTimezone($dbtz); + // Set the range + return new Q(array( + "{$name}__range" => array( + $start->format('Y-m-d H:i:s'), + $end->format('Y-m-d H:i:s') + ) + )); + break; default: return parent::getSearchQ($method, $value, $name); } @@ -2347,6 +2388,8 @@ class DatetimeField extends FormField { return __('%1$s is in the future'); case 'past': return __('%1$s is in the past'); + case 'period': + return __('%1$s is %2$s'); default: return parent::describeSearchMethod($method); } @@ -2375,6 +2418,8 @@ class DatetimeField extends FormField { case 'before': case 'after': return sprintf($desc, $name, $this->toString($value)); + case 'period': + return sprintf($desc, $name, self::periods($value) ?: $value); default: return parent::describeSearch($method, $value, $name); } @@ -3268,7 +3313,7 @@ class FileUploadField extends FormField { $id = $F->getId(); // This file is allowed for attachment in this session - $_SESSION[':uploadedFiles'][$id] = 1; + $_SESSION[':uploadedFiles'][$id] = $F->getName(); return $id; } @@ -3357,6 +3402,10 @@ class FileUploadField extends FormField { if ($a && ($f=$a->getFile())) $files[] = $f; } + + foreach (@$this->getClean() as $key => $value) + $files[] = array('id' => $key, 'name' => $value); + $this->files = $files; } return $this->files; @@ -3427,9 +3476,7 @@ class FileUploadField extends FormField { } function parse($value) { - // Values in the database should be integer file-ids - return array_map(function($e) { return (int) $e; }, - $value ?: array()); + return $value; } function to_php($value) { @@ -4400,13 +4447,7 @@ class FileUploadWidget extends Widget { ); $maxfilesize = ($config['size'] ?: 1048576) / 1048576; $files = array(); - $new = array_flip($this->field->getClean()); - - //get file ids stored in session when creating tickets/tasks from thread - //XXX: This shouldn't be here!! - if (!$new && is_array($_SESSION[':form-data']) - && array_key_exists($this->field->get('name'), $_SESSION[':form-data'])) - $new = $_SESSION[':form-data'][$this->field->get('name')]; + $new = $this->field->getClean(); foreach ($this->field->getAttachments() as $att) { unset($new[$att->file_id]); @@ -4425,6 +4466,7 @@ class FileUploadWidget extends Widget { $F = AttachmentFile::objects() ->filter(array('id__in' => array_keys($new))) ->all(); + foreach ($F as $f) { $f->tmp_name = $new[$f->getId()]; $files[] = array( @@ -4473,7 +4515,7 @@ class FileUploadWidget extends Widget { foreach (AttachmentFile::format($_FILES[$this->name]) as $file) { try { $F = $this->field->uploadFile($file); - $ids[] = $F->getId(); + $ids[$F->getId()] = $F->getName(); } catch (FileUploadError $ex) {} } @@ -4487,38 +4529,37 @@ class FileUploadWidget extends Widget { if (!($files = parent::getValue())) return array(); + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $_files = array(); + foreach ($files as $info) { + if (@list($id, $name) = explode(',', $info, 2)) + $_files[$id] = $name; + } + $files = $_files; + } + $allowed = array(); // Files already attached to the field are allowed foreach ($this->field->getFiles() as $F) { // FIXME: This will need special porting in v1.10 - $allowed[$F->id] = 1; + $allowed[$F->id] = $F->getName(); } // New files uploaded in this session are allowed if (isset($_SESSION[':uploadedFiles'])) $allowed += $_SESSION[':uploadedFiles']; - // Files attached to threads where we are creating tasks/tickets are allowed - if (isset($_SESSION[':form-data'][$this->field->get('name')])) { - foreach ($_SESSION[':form-data'][$this->field->get('name')] as $key => $value) - $allowed[$key] = $value; - } - // Canned attachments initiated by this session if (isset($_SESSION[':cannedFiles'])) $allowed += $_SESSION[':cannedFiles']; // Parse the files and make sure it's allowed. - foreach ($files as $info) { - @list($id, $name) = explode(',', $info, 2); + foreach ($files as $id => $name) { if (!isset($allowed[$id])) continue; // Keep the values as the IDs - if ($name) - $ids[$name] = $id; - else - $ids[] = $id; + $ids[$id] = $name; } return $ids; diff --git a/include/class.misc.php b/include/class.misc.php index 57c18a8df5f0456bd8cce201c7c003ae52fdcee4..65b1c357a677707a480e4819eb21f4796c465713 100644 --- a/include/class.misc.php +++ b/include/class.misc.php @@ -143,6 +143,85 @@ class Misc { return ((float)$usec + (float)$sec); } + // Date range for the period in a given time + function date_range($period, $time=false) { + $time = $time ?: self::gmtime(); + if (!($dt = Format::parseDateTime($time))) + return null; + // Force UTC + $dt->setTimezone(new DateTimeZone('UTC')); + + // Make dt Immutable. + $dt = DateTimeImmutable::createFromMutable($dt); + switch ($period) { + case 'td': + case 'today': + $start = $end = $dt->modify('today'); + break; + case 'yd': + case 'yesterday': + $start = $end = $dt->modify('yesterday'); + break; + case 'tw': + case 'this-week': + $N = $dt->format('N'); + $start = $dt->modify($N == 1 ? 'today' : 'last monday'); + $end = $start->modify('next sunday'); + break; + case 'tm': + case 'this-month'; + $start = $dt->modify('first day of this month'); + $end = $dt->modify('last day of this month'); + break; + case 'tq': + case 'this-quater': + $offset = ($dt->format('m') - 1) % 3; + $start = $dt->modify(" - $offset month") + ->modify('first day of this month'); + $end = $start->modify('+ 3 month')->modify('- 1 day'); + break; + case 'ty': + case 'this-year': + $start = $dt->modify('january')->modify('first day of this month'); + $end = $dt->modify('december')->modify('last day of this month'); + break; + case 'lw': + case 'last-week': + //TODO: address edge cases + $start = $dt->modify('- 1 week')->modify('last monday'); + $end = $start->modify('next sunday'); + break; + case 'lm': + case 'last-month'; + $start = $dt->modify('- 1 month')->modify('first day of this month'); + $end = $start->modify('last day of this month'); + break; + case 'lq': + case 'last-quater': + $offset = (($dt->format('m') - 1) % 3)+3; + $start = $dt->modify(" - $offset month") + ->modify('first day of this month'); + $end = $start->modify('+ 3 month')->modify('- 1 day'); + break; + case 'ly': + case 'last-year': + $start = $dt->modify('- 1 year') + ->modify('january') + ->modify('first day of this month'); + $end = $start->modify('december')->modify('last day of this month'); + break; + default: + return null; + } + + if ($start) + $start = $start->setTime(00, 00, 00); + if ($end) + $end = $end->setTime(23, 59, 59); + + return (object) array('start' => $start, 'end' => $end); + } + //Current page function currentURL() { diff --git a/include/class.queue.php b/include/class.queue.php index 9e9ace88f5b8e9a698e3566a4ab971b53e2a29c5..5d23711784dec4364be188ba6f1308c22108596a 100644 --- a/include/class.queue.php +++ b/include/class.queue.php @@ -667,7 +667,7 @@ class CustomQueue extends VerySimpleModel { "bits" => QueueColumn::FLAG_SORTABLE, "filter" => "link:ticketP", "annotations" => '[{"c":"TicketSourceDecoration","p":"b"}]', - "conditions" => '[{"crit":["isanswered","set",null],"prop":{"font-weight":"bold"}}]', + "conditions" => '[{"crit":["isanswered","nset",null],"prop":{"font-weight":"bold"}}]', )), QueueColumn::placeholder(array( "id" => 2, @@ -686,7 +686,7 @@ class CustomQueue extends VerySimpleModel { "bits" => QueueColumn::FLAG_SORTABLE, "filter" => "link:ticket", "annotations" => '[{"c":"TicketThreadCount","p":">"},{"c":"ThreadAttachmentCount","p":"a"},{"c":"OverdueFlagDecoration","p":"<"}]', - "conditions" => '[{"crit":["isanswered","set",null],"prop":{"font-weight":"bold"}}]', + "conditions" => '[{"crit":["isanswered","nset",null],"prop":{"font-weight":"bold"}}]', "truncate" => 'ellipsis', )), QueueColumn::placeholder(array( diff --git a/include/class.thread.php b/include/class.thread.php index b499b95ed59c497d37d70955079f9501e3b58e80..481a34835aed3ce179a8c83bf8e07b3ed3b84596 100644 --- a/include/class.thread.php +++ b/include/class.thread.php @@ -1082,21 +1082,20 @@ implements TemplateVariable { $files = array($files); $ids = array(); - foreach ($files as $name => $file) { - $F = array('inline' => is_array($file) && @$file['inline']); - - if (is_numeric($file)) - $fileId = $file; - elseif ($file instanceof AttachmentFile) - $fileId = $file->getId(); - elseif (is_array($file) && isset($file['id'])) - $fileId = $file['id']; - elseif ($AF = AttachmentFile::create($file)) + foreach ($files as $id => $info) { + $F = array('inline' => is_array($info) && @$info['inline']); + $AF = null; + + if ($info instanceof AttachmentFile) + $fileId = $info->getId(); + elseif (is_array($info) && isset($info['id'])) + $fileId = $info['id']; + elseif ($AF = AttachmentFile::create($info)) $fileId = $AF->getId(); elseif ($add_error) { - $error = $file['error'] - ?: sprintf(_S('Unable to import attachment - %s'), - $name ?: $file['name']); + $error = $info['error'] + ?: sprintf(_S('Unable to save attachment - %s'), + $info['name'] ?: $info['id']); if (is_numeric($error) && isset($error_descriptions[$error])) { $error = sprintf(_S('Error #%1$d: %2$s'), $error, _S($error_descriptions[$error])); @@ -1119,15 +1118,15 @@ implements TemplateVariable { $F['id'] = $fileId; - if (is_string($name)) - $F['name'] = $name; + if (is_string($info)) + $F['name'] = $info; if (isset($AF)) $F['file'] = $AF; // Add things like the `key` field, but don't change current // keys of the file array - if (is_array($file)) - $F += $file; + if (is_array($info)) + $F += $info; // Key is required for CID rewriting in the body if (!isset($F['key']) && ($AF = AttachmentFile::lookup($F['id']))) @@ -1157,11 +1156,13 @@ implements TemplateVariable { elseif (is_string($name)) { $filename = $name; } + if ($filename) { // This should be a noop since the ORM caches on PK $F = @$file['file'] ?: AttachmentFile::lookup($file['id']); // XXX: This is not Unicode safe - if ($F && 0 !== strcasecmp($F->name, $filename)) + // TODO: fix name lookup + if ($F && strcasecmp($F->name, $filename) !== 0) $att->name = $filename; } @@ -1578,7 +1579,7 @@ implements TemplateVariable { $attached_files = array(); foreach (array( // Web uploads and canned attachments - $vars['files'], $vars['cannedattachments'], + $vars['files'], // Emailed or API attachments $vars['attachments'], // Inline images (attached to the draft) diff --git a/include/class.thread_actions.php b/include/class.thread_actions.php index 2bccfd311586643492e48b0b987f6d33c0a95d2d..54a2821c996b9fa4c3ef64ce8546aea735076825 100644 --- a/include/class.thread_actions.php +++ b/include/class.thread_actions.php @@ -525,6 +525,7 @@ JS foreach ($this->entry->getAttachments() as $a) if (!$a->inline && $a->file) { $_SESSION[':form-data'][$k][$a->file->getId()] = $a->getFilename(); + $_SESSION[':uploadedFiles'][$a->file->getId()] = $a->getFilename(); } } diff --git a/include/class.ticket.php b/include/class.ticket.php index 27b7e6710754b86837c6223c1ac728b8fdffad10..43446e89e67ed43a885f61045ec3266f3f1efbc2 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -534,7 +534,8 @@ implements RestrictedAccess, Threadable, Searchable { } function getSource() { - return $this->source; + $sources = $this->getSources(); + return $sources[$this->source] ?: $this->source; } function getIP() { @@ -549,7 +550,7 @@ implements RestrictedAccess, Threadable, Searchable { global $cfg; return array( - 'source' => $this->getSource(), + 'source' => $this->source, 'topicId' => $this->getTopicId(), 'slaId' => $this->getSLAId(), 'user_id' => $this->getOwnerId(), @@ -1028,7 +1029,7 @@ implements RestrictedAccess, Threadable, Searchable { 'id' => $fid, 'name' => 'source', 'label' => __('Ticket Source'), - 'default' => $this->getSource(), + 'default' => $this->source, 'choices' => Ticket::getSources() )); break; @@ -2836,9 +2837,9 @@ implements RestrictedAccess, Threadable, Searchable { return false; } $files = array(); - foreach ($canned->attachments->getAll() as $file) { - $files[] = $file->file_id; - $_SESSION[':cannedFiles'][$file->file_id] = 1; + foreach ($canned->attachments->getAll() as $att) { + $files[] = array('id' => $att->file_id, 'name' => $att->getName()); + $_SESSION[':cannedFiles'][$att->file_id] = $att->getName(); } if ($cfg->isRichTextEnabled()) @@ -2851,7 +2852,7 @@ implements RestrictedAccess, Threadable, Searchable { $info = array('msgId' => $message instanceof ThreadEntry ? $message->getId() : 0, 'poster' => __('SYSTEM (Canned Reply)'), 'response' => $response, - 'cannedattachments' => $files + 'files' => $files ); $errors = array(); if (!($response=$this->postReply($info, $errors, false, false))) @@ -4087,8 +4088,8 @@ implements RestrictedAccess, Threadable, Searchable { $vars['note'] = ThreadEntryBody::clean($vars['note']); $create_vars = $vars; $tform = TicketForm::objects()->one()->getForm($create_vars); - $create_vars['cannedattachments'] - = $tform->getField('message')->getWidget()->getAttachments()->getClean(); + $create_vars['files'] + = $tform->getField('message')->getWidget()->getAttachments()->getFiles(); if (!($ticket=self::create($create_vars, $errors, 'staff', false))) return false; diff --git a/include/i18n/en_US/templates/ticket/upgraded.yaml b/include/i18n/en_US/templates/ticket/upgraded.yaml index b46a44d854c3849262da9b024b4af64baaee78c8..1ff02c0527cda0e4c8f548a4b68ff64a46792936 100644 --- a/include/i18n/en_US/templates/ticket/upgraded.yaml +++ b/include/i18n/en_US/templates/ticket/upgraded.yaml @@ -13,7 +13,7 @@ subject: osTicket Upgraded! message: | <p> osTicket upgraded successfully! Please refer to the Release Notes - (http://osticket.com/wiki/Release_Notes) for more information about + (https://docs.osticket.com/en/latest/Developer%20Documentation/Changelog.html?highlight=notes) for more information about changes and new features. </p><p> Be sure to join the <a href="http://osticket.com/forums">osTicket diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php index 62a0c60fc0f0c30833e05b6f5619ac3d2717245f..09bcfb21fdf95ee2a05366724b6ee921c63eaf48 100644 --- a/include/staff/ticket-open.inc.php +++ b/include/staff/ticket-open.inc.php @@ -31,6 +31,7 @@ if (!$user && $_GET['tid'] && ($entry = ThreadEntry::lookup($_GET['tid']))) { foreach ($entry->getAttachments() as $a) { if (!$a->inline && $a->file) { $_SESSION[':form-data'][$k][$a->file->getId()] = $a->getFilename(); + $_SESSION[':uploadedFiles'][$a->file->getId()] = $a->getFilename(); } } } diff --git a/include/upgrader/done.inc.php b/include/upgrader/done.inc.php index 2ad200f78b41fd148a91a31696ed83d7c2b66fc7..39c598d7f49a283ca0539f11f024ad57812eefd9 100644 --- a/include/upgrader/done.inc.php +++ b/include/upgrader/done.inc.php @@ -9,7 +9,7 @@ $_SESSION['ost_upgrader']=null; <div id="intro"> <p><?php echo __('Congratulations! osTicket upgrade has been completed successfully.');?></p> <p><?php echo sprintf(__('Please refer to %s for more information about changes and/or new features.'), - sprintf('<a href="http://osticket.com/wiki/Release_Notes" target="_blank">%s</a>', + sprintf('<a href="https://docs.osticket.com/en/latest/Developer%20Documentation/Changelog.html?highlight=notes" target="_blank">%s</a>', __('Release Notes') ));?></p> </div> @@ -26,7 +26,7 @@ $_SESSION['ost_upgrader']=null; <p><b><?php echo __('Post-upgrade');?></b>: <?php echo sprintf(__('You can now go to %s to enable the system and explore the new features. For complete and up-to-date release notes see the %s'), sprintf('<a href="'. ROOT_PATH . 'scp/settings.php" target="_blank">%s</a>', __('Admin Panel')), - sprintf('<a href="http://osticket.com/wiki/Release_Notes" target="_blank">%s</a>', __('osTicket Wiki')));?></p> + sprintf('<a href="https://docs.osticket.com/en/latest/Developer%20Documentation/Changelog.html?highlight=notes" target="_blank">%s</a>', __('osTicket Docs')));?></p> <p><b><?php echo __('Stay up to date');?></b>: <?php echo __("It's important to keep your osTicket installation up to date. Get announcements, security updates and alerts delivered directly to you!");?> <?php echo sprintf(__('%1$s Get in the loop %2$s today and stay informed!'), '<a target="_blank" href="http://osticket.com/newsletter">', '</a>');?></p> <p><b><?php echo __('Commercial Support Available');?></b>: <?php echo sprintf(__('Get guidance and hands-on expertise to address unique challenges and make sure your osTicket runs smoothly, efficiently, and securely. %1$s Learn More! %2$s'), '<a target="_blank" href="http://osticket.com/support">','</a>');?></p> diff --git a/open.php b/open.php index a507bc979515181f5d46eb035a8ccaf9ade92e59..ef1dde53285c8d406c3ba5406fcb3f52df151854 100644 --- a/open.php +++ b/open.php @@ -33,7 +33,7 @@ if ($_POST) { $messageField = $tform->getField('message'); $attachments = $messageField->getWidget()->getAttachments(); if (!$errors && $messageField->isAttachmentsEnabled()) - $vars['cannedattachments'] = $attachments->getClean(); + $vars['files'] = $attachments->getFiles(); // Drop the draft.. If there are validation errors, the content // submitted will be displayed back to the user diff --git a/scp/tasks.php b/scp/tasks.php index 63e4b87ca1b35831e54f6bfcde6ce0efe07620db..5375261863e375f72e088b9958b80967299383b3 100644 --- a/scp/tasks.php +++ b/scp/tasks.php @@ -48,9 +48,7 @@ if($_POST && !$errors): switch(strtolower($_POST['a'])): case 'postnote': /* Post Internal Note */ $vars = $_POST; - $attachments = $note_attachments_form->getField('attachments')->getClean(); - $vars['cannedattachments'] = array_merge( - $vars['cannedattachments'] ?: array(), $attachments); + $vars['files'] = $note_attachments_form->getField('attachments')->getFiles(); $wasOpen = ($task->isOpen()); if(($note=$task->postNote($vars, $errors, $thisstaff))) { @@ -78,9 +76,7 @@ if($_POST && !$errors): break; case 'postreply': /* Post an update */ $vars = $_POST; - $attachments = $reply_attachments_form->getField('attachments')->getClean(); - $vars['cannedattachments'] = array_merge( - $vars['cannedattachments'] ?: array(), $attachments); + $vars['files'] = $reply_attachments_form->getField('attachments')->getFiles(); $wasOpen = ($task->isOpen()); if (($response=$task->postReply($vars, $errors))) { diff --git a/scp/tickets.php b/scp/tickets.php index 4851b4169d257b259671e525d12b0917be428b46..d100f38d7b1af8e1505301922754e5925bc264dc 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -53,7 +53,7 @@ if (!$ticket) { && $_GET['a'] !== 'open' ) { $criteria = [ - ['user__name', 'equal', $user->name], + ['user__emails__address', 'equal', $user->getDefaultEmailAddress()], ['user_id', 'equal', $user->id], ]; if ($S = $_GET['status']) @@ -149,7 +149,7 @@ if($_POST && !$errors): $errors['err'] = __('Action denied. Contact admin for access'); } else { $vars = $_POST; - $vars['cannedattachments'] = $response_form->getField('attachments')->getClean(); + $vars['files'] = $response_form->getField('attachments')->getFiles(); $vars['response'] = ThreadEntryBody::clean($vars['response']); if(!$vars['response']) $errors['response']=__('Response required'); @@ -211,9 +211,7 @@ if($_POST && !$errors): break; case 'postnote': /* Post Internal Note */ $vars = $_POST; - $attachments = $note_form->getField('attachments')->getClean(); - $vars['cannedattachments'] = array_merge( - $vars['cannedattachments'] ?: array(), $attachments); + $vars['files'] = $note_form->getField('attachments')->getFiles(); $vars['note'] = ThreadEntryBody::clean($vars['note']); if ($cfg->isTicketLockEnabled()) { @@ -405,7 +403,7 @@ if($_POST && !$errors): if ($vars['uid'] && !($user=User::lookup($vars['uid']))) $vars['uid'] = 0; - $vars['cannedattachments'] = $response_form->getField('attachments')->getClean(); + $vars['files'] = $response_form->getField('attachments')->getFiles(); if(($ticket=Ticket::open($vars, $errors))) { $msg=__('Ticket created successfully'); @@ -418,6 +416,10 @@ if($_POST && !$errors): $response_form->getField('attachments')->reset(); $_SESSION[':form-data'] = null; } elseif(!$errors['err']) { + // ensure that we retain the tid if ticket is created from thread + if ($_SESSION[':form-data']['ticketId'] || $_SESSION[':form-data']['taskId']) + $_GET['tid'] = $_SESSION[':form-data']['ticketId'] ?: $_SESSION[':form-data']['taskId']; + $errors['err']=sprintf('%s %s', __('Unable to create the ticket.'), __('Correct any errors below and try again.')); diff --git a/tickets.php b/tickets.php index fa88e5e55775b4aeff32dda04841b35eed6fc178..560b16f3dc963008e05aa8c610607b82992fee95 100644 --- a/tickets.php +++ b/tickets.php @@ -84,7 +84,7 @@ if ($_POST && is_object($ticket) && $ticket->getId()) { 'poster' => (string) $thisclient->getName(), 'message' => $_POST['message'] ); - $vars['cannedattachments'] = $attachments->getClean(); + $vars['files'] = $attachments->getFiles(); if (isset($_POST['draft_id'])) $vars['draft_id'] = $_POST['draft_id'];