Newer
Older
<?php
/*********************************************************************
class.thread.php
XXX: Please DO NOT add any ticket related logic! use ticket class.
Peter Rotich <peter@osticket.com>
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.ticket.php');
include_once(INCLUDE_DIR.'class.draft.php');
include_once(INCLUDE_DIR.'class.role.php');
//Ticket thread.
class Thread extends VerySimpleModel {
static $meta = array(
'table' => THREAD_TABLE,
'pk' => array('id'),
'joins' => array(
'ticket' => array(
'constraint' => array(
'object_type' => "'T'",
'object_id' => 'TicketModel.ticket_id',
'task' => array(
'constraint' => array(
'object_type' => "'A'",
'object_id' => 'Task.id',
),
),
'collaborators' => array(
'reverse' => 'Collaborator.thread',
),
'entries' => array(
'reverse' => 'ThreadEntry.thread',
'events' => array(
'reverse' => 'ThreadEvent.thread',
'broker' => 'ThreadEvents',
const MODE_STAFF = 1;
const MODE_CLIENT = 2;
var $_object;
var $_collaborators; // Cache for collabs
return $this->id;
return $this->object_id;
return $this->object_type;
function getObject() {
if (!$this->_object)
$this->_object = ObjectModel::lookup(
$this->getObjectId(), $this->getObjectType());
return $this->_object;
}
function getNumAttachments() {
return Attachment::objects()->filter(array(
'thread_entry__thread' => $this
))->count();
return $this->entries->count();
}
function getEntries($criteria=false) {
if (!isset($this->_entries)) {
$this->_entries = $this->entries->annotate(array(
'has_attachments' => SqlAggregate::COUNT(SqlCase::N()
->when(array('attachments__inline'=>0), 1)
->otherwise(null)
),
));
$this->_entries->exclude(array('flags__hasbit'=>ThreadEntry::FLAG_HIDDEN));
if ($criteria)
$this->_entries->filter($criteria);
}
return $this->_entries;
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Collaborators
function getNumCollaborators() {
return $this->collaborators->count();
}
function getNumActiveCollaborators() {
if (!isset($this->ht['active_collaborators']))
$this->ht['active_collaborators'] = count($this->getActiveCollaborators());
return $this->ht['active_collaborators'];
}
function getActiveCollaborators() {
return $this->getCollaborators(array('isactive'=>1));
}
function getCollaborators($criteria=array()) {
if ($this->_collaborators && !$criteria)
return $this->_collaborators;
$collaborators = $this->collaborators
->filter(array('thread_id' => $this->getId()));
if (isset($criteria['isactive']))
$collaborators->filter(array('isactive' => $criteria['isactive']));
// TODO: sort by name of the user
$collaborators->order_by('user__name');
if (!$criteria)
$this->_collaborators = $collaborators;
return $collaborators;
}
function addCollaborator($user, $vars, &$errors, $event=true) {
if (!$user)
return null;
$vars = array_merge(array(
'threadId' => $this->getId(),
'userId' => $user->getId()), $vars);
if (!($c=Collaborator::add($vars, $errors)))
return null;
$this->_collaborators = null;
if ($event)
$this->getEvents()->log($this->getObject(),
'collab',
array('add' => array($user->getId() => array(
'name' => $user->getName()->getOriginal(),
'src' => @$vars['source'],
))
)
);
return $c;
}
function updateCollaborators($vars, &$errors) {
global $thisstaff;
if (!$thisstaff) return;
//Deletes
if($vars['del'] && ($ids=array_filter($vars['del']))) {
$collabs = array();
foreach ($ids as $k => $cid) {
if (($c=Collaborator::lookup($cid))
&& $c->getThreadId() == $this->getId()
&& $c->delete())
$collabs[] = $c;
}
$this->getEvents()->log($this->getObject(), 'collab', array(
'del' => array($c->user_id => array('name' => $c->getName()->getOriginal()))
));
}
//statuses
$cids = null;
if($vars['cid'] && ($cids=array_filter($vars['cid']))) {
$this->collaborators->filter(array(
'thread_id' => $this->getId(),
'id__in' => $cids
))->update(array(
'updated' => SqlFunction::NOW(),
'isactive' => 1,
));
}
if ($cids) {
$this->collaborators->filter(array(
'thread_id' => $this->getId(),
Q::not(array('id__in' => $cids))
))->update(array(
'updated' => SqlFunction::NOW(),
'isactive' => 0,
));
}
unset($this->ht['active_collaborators']);
$this->_collaborators = null;
return true;
}
//UserList of participants (collaborators)
function getParticipants() {
if (!isset($this->_participants)) {
$list = new UserList();
if ($collabs = $this->getActiveCollaborators()) {
foreach ($collabs as $c)
$list->add($c);
}
$this->_participants = $list;
}
return $this->_participants;
}
function render($type=false, $options=array()) {
$mode = $options['mode'] ?: self::MODE_STAFF;
// Register thread actions prior to rendering the thread.
if (!class_exists('tea_showemailheaders'))
include_once INCLUDE_DIR . 'class.thread_actions.php';
$entries = $this->getEntries();
if ($type && is_array($type))
$entries->filter(array('type__in' => $type));
if ($options['sort'] && !strcasecmp($options['sort'], 'DESC'))
$entries->order_by('-id');
// Precache all the attachments on this thread
AttachmentFile::objects()->filter(array(
'attachments__thread_entry__thread__id' => $this->id
))->all();
$inc = ($mode == self::MODE_STAFF) ? STAFFINC_DIR : CLIENTINC_DIR;
include $inc . 'templates/thread-entries.tmpl.php';
function getEvents() {
return $this->events;
}
/**
* postEmail
*
* After some security and sanity checks, attaches the body and subject
* of the message in reply to this thread item
*
* Parameters:
* mailinfo - (array) of information about the email, with at least the
* following keys
* - mid - (string) email message-id
* - name - (string) personal name of email originator
* - email - (string<email>) originating email address
* - subject - (string) email subject line (decoded)
* - body - (string) email message body (decoded)
*/
function postEmail($mailinfo, $entry=null) {
// +==================+===================+=============+
// | Orig Thread-Type | Reply Thread-Type | Requires |
// +==================+===================+=============+
// | * | Message (M) | From: Owner |
// | * | Note (N) | From: Staff |
// | Response (R) | Message (M) | |
// | Message (M) | Response (R) | From: Staff |
// +------------------+-------------------+-------------+
if (!$object = $this->getObject()) {
// How should someone find this thread?
return false;
}
elseif ($object instanceof Ticket && (
!$mailinfo['staffId']
&& $object->isClosed()
&& !$object->isReopenable()
)) {
// Ticket is closed, not reopenable, and email was not submitted
// by an agent. Email cannot be submitted
return false;
}
$vars = array(
'mid' => $mailinfo['mid'],
'header' => $mailinfo['header'],
'poster' => $mailinfo['name'],
'origin' => 'Email',
'source' => 'Email',
'ip' => '',
Loading
Loading full blame...