Skip to content
Snippets Groups Projects
class.thread_actions.php 16.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • <?php
    /*********************************************************************
        class.thread_actions.php
    
        Actions for thread entries. This serves as a simple repository for
        drop-down actions which can be triggered on the ticket-view page for an
        object's thread.
    
        Jared Hancock <jared@osticket.com>
        Peter Rotich <peter@osticket.com>
        Copyright (c)  2006-2014 osTicket
        http://www.osticket.com
    
        Released under the GNU General Public License WITHOUT ANY WARRANTY.
        See LICENSE.TXT for details.
    
        vim: expandtab sw=4 ts=4 sts=4:
    **********************************************************************/
    include_once(INCLUDE_DIR.'class.thread.php');
    
    
    class TEA_ShowEmailRecipients extends ThreadEntryAction {
        static $id = 'emailrecipients';
        static $name = /* trans */ 'View Email Recipients';
        static $icon = 'group';
    
        function isVisible() {
            global $thisstaff;
    
            if ($this->entry->getEmailHeader())
              return ($thisstaff && $this->entry->getEmailHeader());
            elseif ($this->entry->recipients)
              return $this->entry->recipients;
    
        }
    
        function getJsStub() {
            return sprintf("$.dialog('%s');",
                $this->getAjaxUrl()
            );
        }
    
        function trigger() {
            switch ($_SERVER['REQUEST_METHOD']) {
            case 'GET' && $this->entry->recipients:
                return $this->getRecipients();
            case 'GET':
                return $this->trigger__get();
            }
        }
    
        private function trigger__get() {
            $hdr = Mail_parse::splitHeaders(
                    $this->entry->getEmailHeader(), true);
    
            $recipients = array();
            foreach (array('To', 'TO', 'Cc', 'CC', 'Bcc', 'BCC') as $k) {
                if (isset($hdr[$k]) && $hdr[$k] &&
                    ($addresses=Mail_Parse::parseAddressList($hdr[$k]))) {
                    foreach ($addresses as $addr) {
                        $email = sprintf('%s@%s', $addr->mailbox, $addr->host);
                        $name = $addr->personal ?: '';
                        $recipients[$k][] = sprintf('%s<%s>',
                                (($name && strcasecmp($name, $email))? "$name ": ''),
                                $email);
                    }
                }
            }
    
            include STAFFINC_DIR . 'templates/thread-email-recipients.tmpl.php';
        }
    
        private function getRecipients() {
          $recipients = json_decode($this->entry->recipients, true);
    
          include STAFFINC_DIR . 'templates/thread-email-recipients.tmpl.php';
        }
    }
    ThreadEntry::registerAction(/* trans */ 'E-Mail', 'TEA_ShowEmailRecipients');
    
    
    class TEA_ShowEmailHeaders extends ThreadEntryAction {
        static $id = 'view_headers';
        static $name = /* trans */ 'View Email Headers';
        static $icon = 'envelope';
    
    
        function isVisible() {
    
            if (!$this->entry->getEmailHeader())
                return false;
    
            return $thisstaff && $thisstaff->isAdmin();
    
        }
    
        function getJsStub() {
            return sprintf("$.dialog('%s');",
                $this->getAjaxUrl()
            );
        }
    
        function trigger() {
            switch ($_SERVER['REQUEST_METHOD']) {
            case 'GET':
                return $this->trigger__get();
            }
        }
    
        private function trigger__get() {
    
            $headers = $this->entry->getEmailHeader();
    
    
            include STAFFINC_DIR . 'templates/thread-email-headers.tmpl.php';
        }
    }
    ThreadEntry::registerAction(/* trans */ 'E-Mail', 'TEA_ShowEmailHeaders');
    
    
    class TEA_EditThreadEntry extends ThreadEntryAction {
        static $id = 'edit';
        static $name = /* trans */ 'Edit';
        static $icon = 'pencil';
    
        function isVisible() {
            // Can't edit system posts
    
            return ($this->entry->staff_id || $this->entry->user_id)
    
                && $this->entry->type != 'R' && $this->isEnabled();
    
        }
    
        function isEnabled() {
            global $thisstaff;
    
    
            $T = $this->entry->getThread()->getObject();
    
            // You can edit your own posts or posts by your department members
            // if your a manager, or everyone's if your an admin
            return $thisstaff && (
    
                $thisstaff->getId() == $this->entry->staff_id
                || ($T instanceof Ticket
    
                    && $T->getDept()->getManagerId() == $thisstaff->getId()
                )
    
                || ($T instanceof Ticket
    
                    && ($role = $thisstaff->getRole($T->getDeptId(), $T->isAssigned($thisstaff)))
    
                    && $role->hasPerm(ThreadEntry::PERM_EDIT)
    
            );
        }
    
        function getJsStub() {
            return sprintf(<<<JS
    var url = '%s';
    $.dialog(url, [201], function(xhr, resp) {
      var json = JSON.parse(resp);
      if (!json || !json.thread_id)
        return;
    
      $('#thread-entry-'+json.thread_id)
        .attr('id', 'thread-entry-' + json.new_id)
        .html(json.entry)
        .find('.thread-body')
        .delay(500)
        .effect('highlight');
    
    }, {size:'large'});
    JS
            , $this->getAjaxUrl());
        }
    
    
        function trigger() {
            switch ($_SERVER['REQUEST_METHOD']) {
            case 'GET':
                return $this->trigger__get();
            case 'POST':
                return $this->trigger__post();
            }
        }
    
    
        protected function trigger__get() {
            global $cfg, $thisstaff;
    
            $poster = $this->entry->getStaff();
    
    
            include STAFFINC_DIR . 'templates/thread-entry-edit.tmpl.php';
        }
    
    
        function updateEntry($guard=false) {
    
            global $thisstaff;
    
    
            $old = $this->entry;
    
            $new = ThreadEntryBody::fromFormattedText($_POST['body'], $old->format);
    
    Peter Rotich's avatar
    Peter Rotich committed
            if ($new->getClean() == $old->getBody())
    
                // No update was performed
    
                return $old;
    
    
            $entry = ThreadEntry::create(array(
                // Copy most information from the old entry
                'poster' => $old->poster,
                'userId' => $old->user_id,
                'staffId' => $old->staff_id,
                'type' => $old->type,
                'threadId' => $old->thread_id,
    
                'recipients' => $old->recipients,
    
                // Connect the new entry to be a child of the previous
                'pid' => $old->id,
    
    
                // Add in new stuff
    
                'title' => Format::htmlchars($_POST['title']),
    
                'body' => $new,
                'ip_address' => $_SERVER['REMOTE_ADDR'],
            ));
    
            if (!$entry)
    
                return false;
    
    
            // Note, anything that points to the $old entry as PID should remain
            // that way for email header lookups and such to remain consistent
    
    
            if ($old->flags & ThreadEntry::FLAG_EDITED
    
                // If editing another person's edit, make a new entry
                and ($old->editor == $thisstaff->getId() && $old->editor_type == 'S')
    
                and !($old->flags & ThreadEntry::FLAG_GUARDED)
            ) {
                // Replace previous edit --------------------------
                $original = $old->getParent();
    
                // Link the new entry to the old id
                $entry->pid = $old->pid;
    
                // Drop the previous edit, and base this edit off the original
                $old->delete();
                $old = $original;
            }
    
    
            // Move the attachments to the new entry
    
            $old->attachments->filter(array(
                'inline' => false,
            ))->update(array(
    
            // Mark the new entry as edited (but not hidden nor guarded)
            $entry->flags = ($old->flags & ~(ThreadEntry::FLAG_HIDDEN | ThreadEntry::FLAG_GUARDED))
    
                | ThreadEntry::FLAG_EDITED;
    
    
            // Guard against deletes on future edit if requested. This is done
            // if an email was triggered by the last edit. In such a case, it
    
            // should not be replaced by a subsequent edit.
    
            if ($guard)
                $entry->flags |= ThreadEntry::FLAG_GUARDED;
    
    
            // Log the editor
            $entry->editor = $thisstaff->getId();
            $entry->editor_type = 'S';
    
            // Sort in the same place in the thread
    
            $entry->created = $old->created;
            $entry->updated = SqlFunction::NOW();
    
            $entry->save(true);
    
    
            // Hide the old entry from the object thread
            $old->flags |= ThreadEntry::FLAG_HIDDEN;
            $old->save();
    
    
            return $entry;
        }
    
        protected function trigger__post() {
            global $thisstaff;
    
            if (!($entry = $this->updateEntry()))
                return $this->trigger__get();
    
    
            ob_start();
            include STAFFINC_DIR . 'templates/thread-entry.tmpl.php';
            $content = ob_get_clean();
    
    
            Http::response('201', JsonDataEncoder::encode(array(
    
                'thread_id' => $this->entry->id, # This is the old id!
    
                'new_id' => $entry->id,
    
                'entry' => $content,
    
            )));
        }
    }
    ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_EditThreadEntry');
    
    class TEA_OrigThreadEntry extends ThreadEntryAction {
        static $id = 'previous';
    
        static $name = /* trans */ 'View History';
        static $icon = 'copy';
    
    
        function isVisible() {
            // Can't edit system posts
            return $this->entry->flags & ThreadEntry::FLAG_EDITED;
        }
    
        function getJsStub() {
            return sprintf("$.dialog('%s');",
                $this->getAjaxUrl()
            );
        }
    
        function trigger() {
            switch ($_SERVER['REQUEST_METHOD']) {
            case 'GET':
                return $this->trigger__get();
            }
        }
    
        private function trigger__get() {
    
            global $thisstaff;
    
            if (!$this->entry->getParent())
    
                Http::response(404, 'No history for this entry');
    
            $entry = $this->entry;
    
            include STAFFINC_DIR . 'templates/thread-entry-view.tmpl.php';
        }
    }
    ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_OrigThreadEntry');
    
    class TEA_EditAndResendThreadEntry extends TEA_EditThreadEntry {
        static $id = 'edit_resend';
    
        static $name = /* trans */ 'Edit and Resend';
        static $icon = 'reply-all';
    
        function isVisible() {
            // Can only resend replies
    
            return $this->entry->staff_id && $this->entry->type == 'R'
                && $this->isEnabled();
    
        }
    
        protected function trigger__post() {
            $resend = @$_POST['commit'] == 'resend';
    
            if (!($entry = $this->updateEntry($resend)))
                return $this->trigger__get();
    
    
            if ($resend)
    
                $this->resend($entry);
    
    
            ob_start();
            include STAFFINC_DIR . 'templates/thread-entry.tmpl.php';
            $content = ob_get_clean();
    
    
            Http::response('201', JsonDataEncoder::encode(array(
    
                'thread_id' => $this->entry->id, # This is the old id!
    
                'new_id' => $entry->id,
    
                'entry' => $content,
    
            )));
        }
    
        function resend($response) {
            global $cfg, $thisstaff;
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            if (!($object = $response->getThread()->getObject()))
                return false;
    
    Peter Rotich's avatar
    Peter Rotich committed
            $vars = $_POST;
            $dept = $object->getDept();
    
            $poster = $response->getStaff();
    
    
            if ($thisstaff && $vars['signature'] == 'mine')
                $signature = $thisstaff->getSignature();
    
            elseif ($poster && $vars['signature'] == 'theirs')
                $signature = $poster->getSignature();
    
            elseif ($vars['signature'] == 'dept' && $dept && $dept->isPublic())
                $signature = $dept->getSignature();
            else
                $signature = '';
    
            $variables = array(
                'response' => $response,
                'signature' => $signature,
                'staff' => $response->getStaff(),
                'poster' => $response->getStaff());
            $options = array('thread' => $response);
    
    
    Peter Rotich's avatar
    Peter Rotich committed
            // Resend response to collabs
            if (($object instanceof Ticket)
                    && ($email=$dept->getEmail())
                    && ($tpl = $dept->getTemplate())
                    && ($msg=$tpl->getReplyMsgTemplate())) {
    
    
                $recipients = json_decode($response->recipients, true);
    
    
    Peter Rotich's avatar
    Peter Rotich committed
                $msg = $object->replaceVars($msg->asArray(),
                    $variables + array('recipient' => $object->getOwner()));
    
    
                $attachments = $cfg->emailAttachments()
                    ? $response->getAttachments() : array();
    
    Peter Rotich's avatar
    Peter Rotich committed
                $email->send($object->getOwner(), $msg['subj'], $msg['body'],
    
                    $attachments, $options, $recipients);
    
            }
            // TODO: Add an option to the dialog
    
            if ($object instanceof Task)
              $object->notifyCollaborators($response, array('signature' => $signature));
    
    
            // Log an event that the item was resent
    
    Peter Rotich's avatar
    Peter Rotich committed
            $object->logEvent('resent', array('entry' => $response->id));
    
    
            // Flag the entry as resent
            $response->flags |= ThreadEntry::FLAG_RESENT;
            $response->save();
    
    ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_EditAndResendThreadEntry');
    
    class TEA_ResendThreadEntry extends TEA_EditAndResendThreadEntry {
        static $id = 'resend';
        static $name = /* trans */ 'Resend';
        static $icon = 'reply-all';
    
        function isVisible() {
            // Can only resend replies
            return $this->entry->staff_id && $this->entry->type == 'R'
                && !parent::isEnabled();
        }
        function isEnabled() {
            return true;
        }
    
        protected function trigger__get() {
            global $cfg, $thisstaff;
    
            $poster = $this->entry->getStaff();
    
            include STAFFINC_DIR . 'templates/thread-entry-resend.tmpl.php';
        }
    
        protected function trigger__post() {
            $resend = @$_POST['commit'] == 'resend';
    
            if (@$_POST['commit'] == 'resend')
                $this->resend($this->entry);
    
            Http::response('201', 'Okee dokey');
        }
    }
    
    ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_ResendThreadEntry');
    
    /* Create a new ticket from thread entry as description */
    class TEA_CreateTicket extends ThreadEntryAction {
        static $id = 'create_ticket';
        static $name = /* trans */ 'Create Ticket';
        static $icon = 'plus';
    
        function isVisible() {
            global $thisstaff;
    
            return $thisstaff && $thisstaff->hasPerm(Ticket::PERM_CREATE, false);
        }
    
        function getJsStub() {
            return sprintf(<<<JS
             window.location.href = '%s';
    JS
            , $this->getCreateTicketUrl()
            );
        }
    
        function trigger() {
            switch ($_SERVER['REQUEST_METHOD']) {
            case 'GET':
                return $this->trigger__get();
            }
        }
    
        private function trigger__get() {
            Http::redirect($this->getCreateTicketUrl());
        }
    
        private function getCreateTicketUrl() {
            return sprintf('tickets.php?a=open&tid=%d', $this->entry->getId());
        }
    }
    
    ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_CreateTicket');
    
    
    
    class TEA_CreateTask extends ThreadEntryAction {
        static $id = 'create_task';
        static $name = /* trans */ 'Create Task';
        static $icon = 'plus';
    
        function isVisible() {
            global $thisstaff;
    
            return $thisstaff && $thisstaff->hasPerm(Task::PERM_CREATE, false);
        }
    
        function getJsStub() {
            return sprintf(<<<JS
    var url = '%s';
    var redirect = $(this).data('redirect');
    $.dialog(url, [201], function(xhr, resp) {
        if (!!redirect)
    
            $.pjax({url: redirect, container: '#pjax-container'});
    
            $.pjax({url: '%s.php?id=%d#tasks', container: '#pjax-container'});
    
            , $this->getAjaxUrl(),
    
            $this->entry->getThread()->getObjectType() == 'T' ? 'tickets' : 'tasks',
    
            $this->entry->getThread()->getObjectId()
    
            );
        }
    
        function trigger() {
            switch ($_SERVER['REQUEST_METHOD']) {
            case 'GET':
                return $this->trigger__get();
    
            case 'POST':
                return $this->trigger__post();
    
            }
        }
    
        private function trigger__get() {
    
            $vars = array(
    
                    'description' => Format::htmlchars($this->entry->getBody()));
    
    
            $_SESSION[':form-data']['tid'] = $this->entry->getThread()->getObJectId();
            $_SESSION[':form-data']['eid'] = $this->entry->getId();
            $_SESSION[':form-data']['timestamp'] = $this->entry->getCreateDate();
            $_SESSION[':form-data']['type'] = $this->entry->getThread()->object_type;
    
    
            if (($f= TaskForm::getInstance()->getField('description'))) {
                  $k = 'attach:'.$f->getId();
    
                  unset($_SESSION[':form-data'][$k]);
    
                  foreach ($this->entry->getAttachments() as $a)
    
                      if (!$a->inline && $a->file) {
                        $_SESSION[':form-data'][$k][] = $a->file->getId();
                      }
    
            if ($this->entry->getThread()->getObjectType()  == 'T')
    
    aydreeihn's avatar
    aydreeihn committed
              return $this->getTicketsAPI()->addTask($this->getObjectId(), $vars);
    
            else
              return $this->getTasksAPI()->add($this->getObjectId(), $vars);
    
    
    
        private function trigger__post() {
    
          if ($this->entry->getThread()->getObjectType()  == 'T')
    
    aydreeihn's avatar
    aydreeihn committed
            return $this->getTicketsAPI()->addTask($this->getObjectId());
    
    aydreeihn's avatar
    aydreeihn committed
            return $this->getTasksAPI()->add($this->getObjectId());
    
    }
    ThreadEntry::registerAction(/* trans */ 'Manage', 'TEA_CreateTask');