Exemplo n.º 1
0
 function showTab()
 {
     @($org = DevblocksPlatform::importGPC($_REQUEST['org_id']));
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl_path = dirname(dirname(__FILE__)) . '/templates/';
     $tpl->assign('path', $tpl_path);
     $contact = DAO_ContactOrg::get($org);
     $tpl->assign('contact', $contact);
     $defaults = new C4_AbstractViewModel();
     $defaults->class_name = 'View_ContactOrg';
     $defaults->id = View_ContactOrg::DEFAULT_ID;
     $view = C4_AbstractViewLoader::getView(View_ContactOrg::DEFAULT_ID, $defaults);
     $view->params = array(new DevblocksSearchCriteria(SearchFields_ContactOrg::PARENT_ORG_ID, '=', $contact->id));
     $tpl->assign('view', $view);
     $tpl->assign('contacts_page', 'orgs');
     $tpl->assign('response_uri', 'contacts/orgs');
     $tpl->assign('view_fields', View_ContactOrg::getFields());
     $tpl->assign('view_searchable_fields', View_ContactOrg::getSearchFields());
     $tpl->display('file:' . $tpl_path . 'childorgs.tpl');
     exit;
 }
Exemplo n.º 2
0
 private function _handleImportContact($xml)
 {
     $settings = CerberusSettings::getInstance();
     $logger = DevblocksPlatform::getConsoleLog();
     $sFirstName = (string) $xml->first_name;
     $sLastName = (string) $xml->last_name;
     $sEmail = (string) $xml->email;
     $sPassword = (string) $xml->password;
     $sOrganization = (string) $xml->organization;
     // Dupe check org
     if (null != ($address = DAO_Address::lookupAddress($sEmail))) {
         $logger->info('[Importer] Avoiding creating duplicate contact #' . $address->id . ' (' . $sEmail . ')');
         // [TODO] Still associate with org if local blank?
         // [TODO] Still associate password if local blank?
         return true;
     }
     $fields = array(DAO_Address::FIRST_NAME => $sFirstName, DAO_Address::LAST_NAME => $sLastName, DAO_Address::EMAIL => $sEmail);
     // Associate SC password
     if (!empty($sPassword) && $sPassword != md5('')) {
         $fields[DAO_Address::IS_REGISTERED] = 1;
         $fields[DAO_Address::PASS] = $sPassword;
     }
     $address_id = DAO_Address::create($fields);
     // Associate with organization
     if (!empty($sOrganization)) {
         if (null != ($org_id = DAO_ContactOrg::lookup($sOrganization, true))) {
             DAO_Address::update($address_id, array(DAO_Address::CONTACT_ORG_ID => $org_id));
         }
     }
     $logger->info('[Importer] Imported contact #' . $address_id . ' (' . $sEmail . ')');
     return true;
 }
Exemplo n.º 3
0
 function getSourceInfo($object_id)
 {
     if (null == ($contact_org = DAO_ContactOrg::get($object_id))) {
         return;
     }
     $url = DevblocksPlatform::getUrlService();
     return array('name' => '[Org] ' . $contact_org->name, 'url' => $url->write(sprintf('c=contacts&a=orgs&display=display&id=%d', $object_id), true));
 }
Exemplo n.º 4
0
 function showConversationAction()
 {
     @($id = DevblocksPlatform::importGPC($_REQUEST['ticket_id'], 'integer'));
     @($expand_all = DevblocksPlatform::importGPC($_REQUEST['expand_all'], 'integer', '0'));
     @($active_worker = CerberusApplication::getActiveWorker());
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl->assign('path', $this->_TPL_PATH);
     $tpl->assign('expand_all', $expand_all);
     $ticket = DAO_Ticket::getTicket($id);
     $tpl->assign('ticket', $ticket);
     $tpl->assign('requesters', $ticket->getRequesters());
     $messages = $ticket->getMessages();
     arsort($messages);
     $tpl->assign('latest_message_id', key($messages));
     $tpl->assign('messages', $messages);
     // Thread comments and messages on the same level
     $convo_timeline = array();
     // Track senders and their orgs
     $message_senders = array();
     $message_sender_orgs = array();
     // Loop messages
     foreach ($messages as $message_id => $message) {
         /* @var $message CerberusMessage */
         $key = $message->created_date . '_m' . $message_id;
         // build a chrono index of messages
         $convo_timeline[$key] = array('m', $message_id);
         // If we haven't cached this sender address yet
         if (!isset($message_senders[$message->address_id])) {
             if (null != ($sender_addy = DAO_Address::get($message->address_id))) {
                 $message_senders[$sender_addy->id] = $sender_addy;
                 // If we haven't cached this sender org yet
                 if (!isset($message_sender_orgs[$sender_addy->contact_org_id])) {
                     if (null != ($sender_org = DAO_ContactOrg::get($sender_addy->contact_org_id))) {
                         $message_sender_orgs[$sender_org->id] = $sender_org;
                     }
                 }
             }
         }
     }
     $tpl->assign('message_senders', $message_senders);
     $tpl->assign('message_sender_orgs', $message_sender_orgs);
     @($mail_inline_comments = DAO_WorkerPref::get($active_worker->id, 'mail_inline_comments', 1));
     if ($mail_inline_comments) {
         // if inline comments are enabled
         $comments = DAO_TicketComment::getByTicketId($id);
         arsort($comments);
         $tpl->assign('comments', $comments);
         // build a chrono index of comments
         foreach ($comments as $comment_id => $comment) {
             /* @var $comment Model_TicketComment */
             $key = $comment->created . '_c' . $comment_id;
             $convo_timeline[$key] = array('c', $comment_id);
         }
     }
     // sort the timeline
     if (!$expand_all) {
         krsort($convo_timeline);
     } else {
         ksort($convo_timeline);
     }
     $tpl->assign('convo_timeline', $convo_timeline);
     // Message Notes
     $notes = DAO_MessageNote::getByTicketId($id);
     $message_notes = array();
     // Index notes by message id
     if (is_array($notes)) {
         foreach ($notes as $note) {
             if (!isset($message_notes[$note->message_id])) {
                 $message_notes[$note->message_id] = array();
             }
             $message_notes[$note->message_id][$note->id] = $note;
         }
     }
     $tpl->assign('message_notes', $message_notes);
     // Message toolbar items
     $messageToolbarItems = DevblocksPlatform::getExtensions('cerberusweb.message.toolbaritem', true);
     if (!empty($messageToolbarItems)) {
         $tpl->assign('message_toolbaritems', $messageToolbarItems);
     }
     // Workers
     $workers = DAO_Worker::getAll();
     $tpl->assign('workers', $workers);
     $tpl->register_modifier('makehrefs', array('CerberusUtils', 'smarty_modifier_makehrefs'));
     $tpl->display('file:' . $this->_TPL_PATH . 'display/modules/conversation/index.tpl');
 }
Exemplo n.º 5
0
 function showTab()
 {
     @($ticket_id = DevblocksPlatform::importGPC($_REQUEST['ticket_id'], 'integer', 0));
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl_path = dirname(dirname(__FILE__)) . '/templates/';
     $tpl->assign('path', $tpl_path);
     $tpl->cache_lifetime = "0";
     $ticket = DAO_Ticket::getTicket($ticket_id);
     $tpl->assign('ticket_id', $ticket_id);
     $address = DAO_Address::get($ticket->first_wrote_address_id);
     $tpl->assign('address', $address);
     if (null == ($view = C4_AbstractViewLoader::getView('', 'ticket_opps'))) {
         $view = new C4_CrmOpportunityView();
         $view->id = 'ticket_opps';
     }
     if (!empty($address->contact_org_id)) {
         // org
         @($org = DAO_ContactOrg::get($address->contact_org_id));
         $view->name = "Org: " . $org->name;
         $view->params = array(SearchFields_CrmOpportunity::ORG_ID => new DevblocksSearchCriteria(SearchFields_CrmOpportunity::ORG_ID, '=', $org->id));
     } else {
         // address
         $view->name = "Requester: " . $address->email;
         $view->params = array(SearchFields_CrmOpportunity::PRIMARY_EMAIL_ID => new DevblocksSearchCriteria(SearchFields_CrmOpportunity::PRIMARY_EMAIL_ID, '=', $ticket->first_wrote_address_id));
     }
     C4_AbstractViewLoader::setView($view->id, $view);
     $tpl->assign('view', $view);
     $tpl->display('file:' . $tpl_path . 'crm/opps/ticket/tab.tpl');
 }
Exemplo n.º 6
0
 private function _deleteIdAction($path)
 {
     $in_id = array_shift($path);
     if (empty($in_id)) {
         $this->_error("ID was not provided.");
     }
     if (null == ($contact_org = DAO_ContactOrg::get($in_id))) {
         $this->_error("ID is not valid.");
     }
     DAO_ContactOrg::delete($contact_org->id);
     $out_xml = new SimpleXMLElement('<success></success>');
     $this->_render($out_xml->asXML());
 }
Exemplo n.º 7
0
 function getOrgsAutoCompletionsAction()
 {
     @($starts_with = DevblocksPlatform::importGPC($_REQUEST['q'], 'string', ''));
     $params = array(DAO_ContactOrg::NAME => $starts_with);
     list($orgs, $null) = DAO_ContactOrg::search(array(), array(new DevblocksSearchCriteria(SearchFields_ContactOrg::NAME, DevblocksSearchCriteria::OPER_LIKE, $starts_with . '*')), -1, 0, SearchFields_ContactOrg::NAME, true, false);
     foreach ($orgs as $val) {
         echo $val[SearchFields_ContactOrg::NAME] . "|";
         echo $val[SearchFields_ContactOrg::ID] . "\n";
     }
     exit;
 }
Exemplo n.º 8
0
 public function getRenderedContent($message_id)
 {
     $raw = $this->content;
     $replace = array();
     $with = array();
     $replace[] = '#timestamp#';
     $with[] = date('r');
     if (!empty($message_id)) {
         $message = DAO_Ticket::getMessage($message_id);
         $ticket = DAO_Ticket::getTicket($message->ticket_id);
         $sender = DAO_Address::get($message->address_id);
         $sender_org = DAO_ContactOrg::get($sender->contact_org_id);
         $replace[] = '#sender_first_name#';
         $replace[] = '#sender_last_name#';
         $replace[] = '#sender_org#';
         $with[] = $sender->first_name;
         $with[] = $sender->last_name;
         $with[] = !empty($sender_org) ? $sender_org->name : "";
         $replace[] = '#ticket_id#';
         $replace[] = '#ticket_mask#';
         $replace[] = '#ticket_subject#';
         $with[] = $ticket->id;
         $with[] = $ticket->mask;
         $with[] = $ticket->subject;
     }
     if (null != ($active_worker = CerberusApplication::getActiveWorker())) {
         $worker = DAO_Worker::getAgent($active_worker->id);
         // most recent info (not session)
         $replace[] = '#worker_first_name#';
         $replace[] = '#worker_last_name#';
         $replace[] = '#worker_title#';
         $with[] = $worker->first_name;
         $with[] = $worker->last_name;
         $with[] = $worker->title;
     }
     return str_replace($replace, $with, $raw);
 }
Exemplo n.º 9
0
 function runMacroAction()
 {
     @($macro_id = DevblocksPlatform::importGPC($_REQUEST['macro_id'], 'integer'));
     @($ids = DevblocksPlatform::importGPC($_REQUEST['ids']));
     @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'], 'string'));
     $view = C4_AbstractViewLoader::getView($view_id);
     $ids = explode(',', $ids);
     if (null !== ($macro = DAO_Macro::get($macro_id))) {
         switch ($macro->source_extension_id) {
             case 'cerberusweb.macros.ticket':
                 $fields = array();
                 // loop over the actions, saving the $params as $fields
                 foreach ($macro->actions as $action => $params) {
                     switch ($action) {
                         case 'cerberusweb.macros.action.assign':
                             $fields['next_worker_id'] = $params['worker_id'];
                             break;
                         case 'cerberusweb.macros.action.move':
                             $fields['team_id'] = $params['group_id'];
                             $fields['category_id'] = $params['bucket_id'];
                             break;
                         case 'cerberusweb.macros.action.status':
                             $fields['is_waiting'] = $params['is_waiting'];
                             $fields['is_closed'] = $params['is_closed'];
                             $fields['is_deleted'] = $params['is_deleted'];
                             break;
                         default:
                             //								$fields[] = $params;
                             break;
                     }
                 }
                 // update the ticket
                 DAO_Ticket::updateTicket($ids, $fields);
                 break;
             case 'cerberusweb.macros.address':
                 foreach ($macro->actions as $action => $params) {
                     switch ($action) {
                         default:
                             DAO_Address::update($ids, $params);
                     }
                 }
                 break;
             case 'cerberusweb.macros.opportunity':
                 foreach ($macro->actions as $action => $params) {
                     switch ($action) {
                         default:
                             DAO_CrmOpportunity::update($ids, $params);
                     }
                 }
             case 'cerberusweb.macros.task':
                 foreach ($macro->actions as $action => $params) {
                     switch ($action) {
                         default:
                             DAO_Task::update($ids, $params);
                     }
                 }
             case 'cerberusweb.macros.organization':
                 foreach ($macro->actions as $action => $params) {
                     switch ($action) {
                         default:
                             DAO_ContactOrg::update($ids, $params);
                     }
                 }
             default:
                 break;
         }
     }
     $view = C4_AbstractViewLoader::getView($view_id);
     $view->render();
 }
Exemplo n.º 10
0
 function showContactHistoryAction()
 {
     $visit = CerberusApplication::getVisit();
     /* @var $visit CerberusVisit */
     $translate = DevblocksPlatform::getTranslationService();
     @($ticket_id = DevblocksPlatform::importGPC($_REQUEST['ticket_id'], 'integer'));
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl->assign('path', $this->_TPL_PATH);
     // Ticket
     $ticket = DAO_Ticket::getTicket($ticket_id);
     $tpl->assign('ticket', $ticket);
     $requesters = $ticket->getRequesters();
     // Addy
     $contact = DAO_Address::get($ticket->first_wrote_address_id);
     $tpl->assign('contact', $contact);
     // Scope
     $scope = $visit->get('display.history.scope', '');
     // [TODO] Sanitize scope preference
     // Defaults
     $defaults = new C4_AbstractViewModel();
     $defaults->class_name = 'C4_TicketView';
     $defaults->id = 'contact_history';
     $defaults->name = $translate->_('addy_book.history.view.title');
     $defaults->view_columns = array(SearchFields_Ticket::TICKET_LAST_ACTION_CODE, SearchFields_Ticket::TICKET_CREATED_DATE, SearchFields_Ticket::TICKET_TEAM_ID, SearchFields_Ticket::TICKET_CATEGORY_ID);
     $defaults->params = array();
     $defaults->renderLimit = 10;
     $defaults->renderSortBy = SearchFields_Ticket::TICKET_CREATED_DATE;
     $defaults->renderSortAsc = false;
     // View
     $view = C4_AbstractViewLoader::getView('contact_history', $defaults);
     // Sanitize scope options
     if ('org' == $scope) {
         if (empty($contact->contact_org_id)) {
             $scope = '';
         }
         if (null == ($contact_org = DAO_ContactOrg::get($contact->contact_org_id))) {
             $scope = '';
         }
     }
     if ('domain' == $scope) {
         $email_parts = explode('@', $contact->email);
         if (!is_array($email_parts) || 2 != count($email_parts)) {
             $scope = '';
         }
     }
     switch ($scope) {
         case 'org':
             $view->params = array(SearchFields_Ticket::TICKET_FIRST_CONTACT_ORG_ID => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_FIRST_CONTACT_ORG_ID, '=', $contact->contact_org_id), SearchFields_Ticket::TICKET_DELETED => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_DELETED, '=', 0));
             $view->name = ucwords($translate->_('contact_org.name')) . ": " . $contact_org->name;
             break;
         case 'domain':
             $view->params = array(SearchFields_Ticket::REQUESTER_ADDRESS => new DevblocksSearchCriteria(SearchFields_Ticket::REQUESTER_ADDRESS, 'like', '*@' . $email_parts[1]), SearchFields_Ticket::TICKET_DELETED => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_DELETED, '=', 0));
             $view->name = ucwords($translate->_('common.email')) . ": *@" . $email_parts[1];
             break;
         default:
         case 'email':
             $scope = 'email';
             $view->params = array(SearchFields_Ticket::REQUESTER_ID => new DevblocksSearchCriteria(SearchFields_Ticket::REQUESTER_ID, 'in', array_keys($requesters)), SearchFields_Ticket::TICKET_DELETED => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_DELETED, '=', 0));
             $view->name = ucwords($translate->_('common.email')) . ": " . $contact->email;
             break;
     }
     $tpl->assign('scope', $scope);
     $view->renderPage = 0;
     $tpl->assign('view', $view);
     C4_AbstractViewLoader::setView($view->id, $view);
     $workers = DAO_Worker::getAll();
     $tpl->assign('workers', $workers);
     $teams = DAO_Group::getAll();
     $tpl->assign('teams', $teams);
     $buckets = DAO_Bucket::getAll();
     $tpl->assign('buckets', $buckets);
     $team_categories = DAO_Bucket::getTeams();
     $tpl->assign('team_categories', $team_categories);
     $tpl->display('file:' . $this->_TPL_PATH . 'display/modules/history/index.tpl');
 }
Exemplo n.º 11
0
 function saveEntryAction()
 {
     $active_worker = CerberusApplication::getActiveWorker();
     // Make sure we're an active worker
     if (empty($active_worker) || empty($active_worker->id)) {
         return;
     }
     @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0));
     @($do_delete = DevblocksPlatform::importGPC($_REQUEST['do_delete'], 'integer', 0));
     @($activity_id = DevblocksPlatform::importGPC($_POST['activity_id'], 'integer', 0));
     @($time_actual_mins = DevblocksPlatform::importGPC($_POST['time_actual_mins'], 'integer', 0));
     @($notes = DevblocksPlatform::importGPC($_POST['notes'], 'string', ''));
     @($org_str = DevblocksPlatform::importGPC($_POST['org'], 'string', ''));
     @($source_extension_id = DevblocksPlatform::importGPC($_POST['source_extension_id'], 'string', ''));
     @($source_id = DevblocksPlatform::importGPC($_POST['source_id'], 'integer', 0));
     // Translate org string into org id, if exists
     $org_id = 0;
     if (!empty($org_str)) {
         $org_id = DAO_ContactOrg::lookup($org_str, true);
     }
     // Delete entries
     if (!empty($id) && !empty($do_delete)) {
         if (null != ($entry = DAO_TimeTrackingEntry::get($id))) {
             // Check privs
             if ($active_worker->hasPriv('timetracking.actions.create') && $active_worker->id == $entry->worker_id || $active_worker->hasPriv('timetracking.actions.update_all')) {
                 DAO_TimeTrackingEntry::delete($id);
             }
         }
         return;
     }
     // New or modify
     $fields = array(DAO_TimeTrackingEntry::ACTIVITY_ID => intval($activity_id), DAO_TimeTrackingEntry::TIME_ACTUAL_MINS => intval($time_actual_mins), DAO_TimeTrackingEntry::NOTES => $notes, DAO_TimeTrackingEntry::DEBIT_ORG_ID => intval($org_id));
     // Only on new
     if (empty($id)) {
         $fields[DAO_TimeTrackingEntry::LOG_DATE] = time();
         $fields[DAO_TimeTrackingEntry::SOURCE_EXTENSION_ID] = $source_extension_id;
         $fields[DAO_TimeTrackingEntry::SOURCE_ID] = intval($source_id);
         $fields[DAO_TimeTrackingEntry::WORKER_ID] = intval($active_worker->id);
     }
     if (empty($id)) {
         // create
         $id = DAO_TimeTrackingEntry::create($fields);
         // Procedurally create a comment
         $translate = DevblocksPlatform::getTranslationService();
         switch ($source_extension_id) {
             // If ticket, add a comment about the timeslip to the ticket
             case 'timetracking.source.ticket':
                 $ticket_id = intval($source_id);
                 if (null != ($worker_address = DAO_Address::lookupAddress($active_worker->email, false))) {
                     if (!empty($activity_id)) {
                         $activity = DAO_TimeTrackingActivity::get($activity_id);
                     }
                     if (!empty($org_id)) {
                         $org = DAO_ContactOrg::get($org_id);
                     }
                     $comment = sprintf("== %s ==\n" . "%s %s\n" . "%s %d\n" . "%s %s (%s)\n" . "%s %s\n" . "%s %s\n", $translate->_('timetracking.ui.timetracking'), $translate->_('timetracking.ui.worker'), $active_worker->getName(), $translate->_('timetracking.ui.comment.time_spent'), $time_actual_mins, $translate->_('timetracking.ui.comment.activity'), !empty($activity) ? $activity->name : '', !empty($activity) && $activity->rate > 0.0 ? $translate->_('timetracking.ui.billable') : $translate->_('timetracking.ui.non_billable'), $translate->_('timetracking.ui.comment.organization'), !empty($org) ? $org->name : $translate->_('timetracking.ui.comment.not_set'), $translate->_('timetracking.ui.comment.notes'), $notes);
                     //timetracking.ui.billable timetracking.ui.non_billable
                     $fields = array(DAO_TicketComment::ADDRESS_ID => intval($worker_address->id), DAO_TicketComment::COMMENT => $comment, DAO_TicketComment::CREATED => time(), DAO_TicketComment::TICKET_ID => intval($ticket_id));
                     DAO_TicketComment::create($fields);
                 }
                 break;
         }
     } else {
         // modify
         DAO_TimeTrackingEntry::update($id, $fields);
     }
     // Custom field saves
     @($field_ids = DevblocksPlatform::importGPC($_POST['field_ids'], 'array', array()));
     DAO_CustomFieldValue::handleFormPost(ChCustomFieldSource_TimeEntry::ID, $id, $field_ids);
 }
Exemplo n.º 12
0
 function showTab()
 {
     $response = DevblocksPlatform::getHttpResponse();
     $path = $response->path;
     array_shift($path);
     // iphone
     array_shift($path);
     // tickets
     array_shift($path);
     // current ('display')
     $id = array_shift($path);
     // ticket id
     @($active_worker = CerberusApplication::getActiveWorker());
     $tpl = DevblocksPlatform::getTemplateService();
     $tpl->assign('path', $this->_TPL_PATH);
     $tpl->assign('expand_all', $expand_all);
     $ticket = DAO_Ticket::getTicket($id);
     $tpl->assign('requesters', $ticket->getRequesters());
     // Drafts
     $drafts = DAO_MailQueue::getWhere(sprintf("%s = %d AND %s = %s", DAO_MailQueue::TICKET_ID, $id, DAO_MailQueue::TYPE, C4_ORMHelper::qstr(Model_MailQueue::TYPE_TICKET_REPLY)));
     if (!empty($drafts)) {
         $tpl->assign('drafts', $drafts);
     }
     // Only unqueued drafts
     $pending_drafts = array();
     if (!empty($drafts) && is_array($drafts)) {
         foreach ($drafts as $draft_id => $draft) {
             if (!$draft->is_queued) {
                 $pending_drafts[$draft_id] = $draft;
             }
         }
     }
     if (!empty($pending_drafts)) {
         $tpl->assign('pending_drafts', $pending_drafts);
     }
     // Messages
     $messages = $ticket->getMessages();
     arsort($messages);
     $tpl->assign('latest_message_id', key($messages));
     $tpl->assign('messages', $messages);
     // Thread comments and messages on the same level
     $convo_timeline = array();
     // Track senders and their orgs
     $message_senders = array();
     $message_sender_orgs = array();
     // Loop messages
     foreach ($messages as $message_id => $message) {
         /* @var $message Model_Message */
         $key = $message->created_date . '_m' . $message_id;
         // build a chrono index of messages
         $convo_timeline[$key] = array('m', $message_id);
         // If we haven't cached this sender address yet
         if (!isset($message_senders[$message->address_id])) {
             if (null != ($sender_addy = DAO_Address::get($message->address_id))) {
                 $message_senders[$sender_addy->id] = $sender_addy;
                 // If we haven't cached this sender org yet
                 if (!isset($message_sender_orgs[$sender_addy->contact_org_id])) {
                     if (null != ($sender_org = DAO_ContactOrg::get($sender_addy->contact_org_id))) {
                         $message_sender_orgs[$sender_org->id] = $sender_org;
                     }
                 }
             }
         }
     }
     $tpl->assign('message_senders', $message_senders);
     $tpl->assign('message_sender_orgs', $message_sender_orgs);
     @($mail_inline_comments = DAO_WorkerPref::get($active_worker->id, 'mail_inline_comments', 1));
     if ($mail_inline_comments) {
         // if inline comments are enabled
         $comments = DAO_TicketComment::getByTicketId($id);
         arsort($comments);
         $tpl->assign('comments', $comments);
         // build a chrono index of comments
         foreach ($comments as $comment_id => $comment) {
             /* @var $comment Model_TicketComment */
             $key = $comment->created . '_c' . $comment_id;
             $convo_timeline[$key] = array('c', $comment_id);
         }
     }
     // Thread drafts into conversation
     if (!empty($drafts)) {
         foreach ($drafts as $draft_id => $draft) {
             /* @var $draft Model_MailQueue */
             $key = $draft->updated . '_d' . $draft_id;
             $convo_timeline[$key] = array('d', $draft_id);
         }
     }
     // sort the timeline
     if (!$expand_all) {
         krsort($convo_timeline);
     } else {
         ksort($convo_timeline);
     }
     $tpl->assign('convo_timeline', $convo_timeline);
     // Message Notes
     $notes = DAO_MessageNote::getByTicketId($id);
     $message_notes = array();
     // Index notes by message id
     if (is_array($notes)) {
         foreach ($notes as $note) {
             if (!isset($message_notes[$note->message_id])) {
                 $message_notes[$note->message_id] = array();
             }
             $message_notes[$note->message_id][$note->id] = $note;
         }
     }
     $tpl->assign('message_notes', $message_notes);
     // Message toolbar items
     $messageToolbarItems = DevblocksPlatform::getExtensions('cerberusweb.message.toolbaritem', true);
     if (!empty($messageToolbarItems)) {
         $tpl->assign('message_toolbaritems', $messageToolbarItems);
     }
     // Workers
     $workers = DAO_Worker::getAll();
     $tpl->assign('workers', $workers);
     $tpl->display('file:' . $this->_TPL_PATH . 'tickets/display/conversation.tpl');
 }