function doSplitMessageAction() { @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); if (null == ($orig_message = DAO_Ticket::getMessage($id))) { return; } if (null == ($orig_headers = $orig_message->getHeaders())) { return; } if (null == ($orig_ticket = DAO_Ticket::getTicket($orig_message->ticket_id))) { return; } if (null == ($messages = DAO_Ticket::getMessagesByTicket($orig_message->ticket_id))) { return; } // Create a new ticket $new_ticket_mask = CerberusApplication::generateTicketMask(); $new_ticket_id = DAO_Ticket::createTicket(array(DAO_Ticket::CREATED_DATE => $orig_message->created_date, DAO_Ticket::UPDATED_DATE => $orig_message->created_date, DAO_Ticket::CATEGORY_ID => $orig_ticket->category_id, DAO_Ticket::FIRST_MESSAGE_ID => $orig_message->id, DAO_Ticket::FIRST_WROTE_ID => $orig_message->address_id, DAO_Ticket::LAST_WROTE_ID => $orig_message->address_id, DAO_Ticket::LAST_ACTION_CODE => CerberusTicketActionCode::TICKET_OPENED, DAO_Ticket::IS_CLOSED => CerberusTicketStatus::OPEN, DAO_Ticket::IS_DELETED => 0, DAO_Ticket::MASK => $new_ticket_mask, DAO_Ticket::SUBJECT => isset($orig_headers['subject']) ? $orig_headers['subject'] : $orig_ticket->subject, DAO_Ticket::TEAM_ID => $orig_ticket->team_id)); // [TODO] SLA? // Copy all the original tickets requesters $orig_requesters = DAO_Ticket::getRequestersByTicket($orig_ticket->id); foreach ($orig_requesters as $orig_req_id => $orig_req_addy) { DAO_Ticket::createRequester($orig_req_id, $new_ticket_id); } // Pull the message off the ticket (reparent) unset($messages[$orig_message->id]); DAO_Message::update($orig_message->id, array(DAO_Message::TICKET_ID => $new_ticket_id)); //[mdf] [CHD-979] The ticket id is also in the message_header table, so update those too $message_headers = DAO_MessageHeader::getAll($orig_message->id); foreach ($message_headers as $hk => $hv) { DAO_MessageHeader::create($orig_message->id, $new_ticket_id, $hk, $hv); } // Reindex the original ticket (last wrote, etc.) $last_message = end($messages); /* @var CerberusMessage $last_message */ DAO_Ticket::updateTicket($orig_ticket->id, array(DAO_Ticket::LAST_WROTE_ID => $last_message->address_id)); // Remove requester if they don't still have messages on the original ticket reset($messages); $found = false; if (is_array($messages)) { foreach ($messages as $msgid => $msg) { if ($msg->address_id == $orig_message->address_id) { $found = true; break; } } } if (!$found) { DAO_Ticket::deleteRequester($orig_ticket->id, $orig_message->address_id); } DevblocksPlatform::redirect(new DevblocksHttpResponse(array('display', $new_ticket_mask))); }
/** * @return Model_WatcherMailFilter[]|false */ static function getMatches(CerberusTicket $ticket, $event, $only_worker_id = null) { $matches = array(); if (!empty($only_worker_id)) { $filters = DAO_WatcherMailFilter::getWhere(sprintf("%s = %d AND %s = %d", DAO_WatcherMailFilter::WORKER_ID, $only_worker_id, DAO_WatcherMailFilter::IS_DISABLED, 0)); } else { $filters = DAO_WatcherMailFilter::getWhere(sprintf("%s = %d", DAO_WatcherMailFilter::IS_DISABLED, 0)); } // [JAS]: Don't send obvious spam to watchers. if ($ticket->spam_score >= 0.9) { return false; } // Build our objects $ticket_from = DAO_Address::get($ticket->last_wrote_address_id); $ticket_group_id = $ticket->team_id; // [TODO] These expensive checks should only populate when needed $messages = DAO_Ticket::getMessagesByTicket($ticket->id); $message_headers = array(); if (empty($messages)) { return false; } if (null != @($message_last = array_pop($messages))) { /* @var $message_last CerberusMessage */ $message_headers = $message_last->getHeaders(); } // Clear the rest of the message manifests unset($messages); $custom_fields = DAO_CustomField::getAll(); // Lazy load when needed on criteria basis $ticket_field_values = null; $address_field_values = null; $org_field_values = null; // Worker memberships (for checking permissions) $workers = DAO_Worker::getAll(); $group_rosters = DAO_Group::getRosters(); // Check filters if (is_array($filters)) { foreach ($filters as $filter) { /* @var $filter Model_WatcherMailFilter */ $passed = 0; // check the worker's group memberships if (!isset($workers[$filter->worker_id]) || $workers[$filter->worker_id]->is_disabled || !$workers[$filter->worker_id]->is_superuser && !isset($group_rosters[$ticket->team_id][$filter->worker_id])) { // no membership continue; } // check criteria foreach ($filter->criteria as $rule_key => $rule) { @($value = $rule['value']); switch ($rule_key) { case 'dayofweek': $current_day = strftime('%w'); //$current_day = 1; // Forced to English abbrevs as indexes $days = array('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'); // Is the current day enabled? if (isset($rule[$days[$current_day]])) { $passed++; } break; case 'timeofday': $current_hour = strftime('%H'); $current_min = strftime('%M'); //$current_hour = 17; //$current_min = 5; if (null != ($from_time = @$rule['from'])) { list($from_hour, $from_min) = explode(':', $from_time); } if (null != ($to_time = @$rule['to'])) { if (list($to_hour, $to_min) = explode(':', $to_time)) { } } // Do we need to wrap around to the next day's hours? if ($from_hour > $to_hour) { // yes $to_hour += 24; // add 24 hrs to the destination (1am = 25th hour) } // Are we in the right 24 hourly range? if ((int) $current_hour >= $from_hour && (int) $current_hour <= $to_hour) { // If we're in the first hour, are we minutes early? if ($current_hour == $from_hour && (int) $current_min < $from_min) { break; } // If we're in the last hour, are we minutes late? if ($current_hour == $to_hour && (int) $current_min > $to_min) { break; } $passed++; } break; case 'event': if (!empty($event) && is_array($rule) && isset($rule[$event])) { $passed++; } break; case 'groups': if (null !== @($group_buckets = $rule['groups'][$ticket->team_id]) && (empty($group_buckets) || in_array($ticket->category_id, $group_buckets))) { $passed++; } break; case 'next_worker_id': // If it's an assigned event, we only care about the filter's owner if (!empty($event) && 0 == strcasecmp($event, 'ticket_assignment')) { if (intval($value) == intval($filter->worker_id)) { $passed++; break; } } if (intval($value) == intval($ticket->next_worker_id)) { $passed++; } break; case 'mask': $regexp_mask = DevblocksPlatform::strToRegExp($value); if (@preg_match($regexp_mask, $ticket->mask)) { $passed++; } break; case 'from': $regexp_from = DevblocksPlatform::strToRegExp($value); if (@preg_match($regexp_from, $ticket_from->email)) { $passed++; } break; case 'subject': $regexp_subject = DevblocksPlatform::strToRegExp($value); if (@preg_match($regexp_subject, $ticket->subject)) { $passed++; } break; case 'body': if (null == ($message_body = $message_last->getContent())) { break; } // Line-by-line body scanning (sed-like) $lines = preg_split("/[\r\n]/", $message_body); if (is_array($lines)) { foreach ($lines as $line) { if (@preg_match($value, $line)) { $passed++; break; } } } break; case 'header1': case 'header2': case 'header3': case 'header4': case 'header5': @($header = strtolower($rule['header'])); if (empty($header)) { $passed++; break; } if (empty($value)) { // we're checking for null/blanks if (!isset($message_headers[$header]) || empty($message_headers[$header])) { $passed++; } } elseif (isset($message_headers[$header]) && !empty($message_headers[$header])) { $regexp_header = DevblocksPlatform::strToRegExp($value); // Flatten CRLF if (@preg_match($regexp_header, str_replace(array("\r", "\n"), ' ', $message_headers[$header]))) { $passed++; } } break; default: // ignore invalids // Custom Fields if (0 == strcasecmp('cf_', substr($rule_key, 0, 3))) { $field_id = substr($rule_key, 3); // Make sure it exists if (null == @($field = $custom_fields[$field_id])) { continue; } // Lazy values loader $field_values = array(); switch ($field->source_extension) { case ChCustomFieldSource_Address::ID: if (null == $address_field_values) { $address_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Address::ID, $ticket_from->id)); } $field_values =& $address_field_values; break; case ChCustomFieldSource_Org::ID: if (null == $org_field_values) { $org_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Org::ID, $ticket_from->contact_org_id)); } $field_values =& $org_field_values; break; case ChCustomFieldSource_Ticket::ID: if (null == $ticket_field_values) { $ticket_field_values = array_shift(DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Ticket::ID, $ticket->id)); } $field_values =& $ticket_field_values; break; } // Type sensitive value comparisons // [TODO] Operators switch ($field->type) { case 'S': // string // string case 'T': // clob // clob case 'U': // URL $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : ''; $oper = isset($rule['oper']) ? $rule['oper'] : "="; if ($oper == "=" && @preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val)) { $passed++; } elseif ($oper == "!=" && @(!preg_match(DevblocksPlatform::strToRegExp($value, true), $field_val))) { $passed++; } break; case 'N': // number $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0; $oper = isset($rule['oper']) ? $rule['oper'] : "="; if ($oper == "=" && intval($field_val) == intval($value)) { $passed++; } elseif ($oper == "!=" && intval($field_val) != intval($value)) { $passed++; } elseif ($oper == ">" && intval($field_val) > intval($value)) { $passed++; } elseif ($oper == "<" && intval($field_val) < intval($value)) { $passed++; } break; case 'E': // date $field_val = isset($field_values[$field_id]) ? intval($field_values[$field_id]) : 0; $from = isset($rule['from']) ? $rule['from'] : "0"; $to = isset($rule['to']) ? $rule['to'] : "now"; if (intval(@strtotime($from)) <= $field_val && intval(@strtotime($to)) >= $field_val) { $passed++; } break; case 'C': // checkbox $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : 0; if (intval($value) == intval($field_val)) { $passed++; } break; case 'D': // dropdown // dropdown case 'X': // multi-checkbox // multi-checkbox case 'M': // multi-picklist // multi-picklist case 'W': // worker $field_val = isset($field_values[$field_id]) ? $field_values[$field_id] : array(); if (!is_array($value)) { $value = array($value); } if (is_array($field_val)) { // if multiple things set foreach ($field_val as $v) { // loop through possible if (isset($value[$v])) { // is any possible set? $passed++; break; } } } else { // single if (isset($value[$field_val])) { // is our set field in possibles? $passed++; break; } } break; } } break; } } // If our rule matched every criteria, stop and return the filter if ($passed == count($filter->criteria)) { DAO_WatcherMailFilter::increment($filter->id); // ++ the times we've matched $matches[$filter->id] = $filter; } } } if (!empty($matches)) { return $matches; } // No matches return false; }
function writeResponse(DevblocksHttpResponse $response) { $tpl = DevblocksPlatform::getTemplateService(); $tpl_path = dirname(dirname(__FILE__)) . '/templates/'; $theme = DAO_CommunityToolProperty::get($this->getPortal(), UmScApp::PARAM_THEME, UmScApp::DEFAULT_THEME); if (!is_dir($tpl_path . 'portal/sc/themes/' . $theme)) { $theme = UmScApp::DEFAULT_THEME; } $umsession = $this->getSession(); $active_user = $umsession->getProperty('sc_login', null); $stack = $response->path; @($module = array_shift($stack)); switch ($module) { default: case 'home': $sHomeRss = DAO_CommunityToolProperty::get($this->getPortal(), UmScApp::PARAM_HOME_RSS, ''); $aHomeRss = !empty($sHomeRss) ? unserialize($sHomeRss) : array(); $feeds = array(); // [TODO] Implement a feed cache so we aren't bombing out foreach ($aHomeRss as $title => $url) { $feed = null; try { $feed = Zend_Feed::import($url); } catch (Exception $e) { } if (!empty($feed) && $feed->count()) { $feeds[] = array('name' => $title, 'feed' => $feed); } } $tpl->assign('feeds', $feeds); $tpl->display("file:{$tpl_path}portal/sc/internal/home/index.tpl"); break; case 'account': if (!$this->allow_logins || empty($active_user)) { break; } $address = DAO_Address::get($active_user->id); $tpl->assign('address', $address); $tpl->display("file:{$tpl_path}portal/sc/internal/account/index.tpl"); break; case 'kb': // KB Roots $sKbRoots = DAO_CommunityToolProperty::get($this->getPortal(), UmScApp::PARAM_KB_ROOTS, ''); $kb_roots = !empty($sKbRoots) ? unserialize($sKbRoots) : array(); $kb_roots_str = '0'; if (!empty($kb_roots)) { $kb_roots_str = implode(',', array_keys($kb_roots)); } switch (array_shift($stack)) { case 'article': if (empty($kb_roots)) { return; } $id = intval(array_shift($stack)); list($articles, $count) = DAO_KbArticle::search(array(new DevblocksSearchCriteria(SearchFields_KbArticle::ID, '=', $id), new DevblocksSearchCriteria(SearchFields_KbArticle::TOP_CATEGORY_ID, 'in', array_keys($kb_roots))), -1, 0, null, null, false); if (!isset($articles[$id])) { break; } $article = DAO_KbArticle::get($id); $tpl->assign('article', $article); @($article_list = $umsession->getProperty(UmScApp::SESSION_ARTICLE_LIST, array())); if (!empty($article) && !isset($article_list[$id])) { DAO_KbArticle::update($article->id, array(DAO_KbArticle::VIEWS => ++$article->views)); $article_list[$id] = $id; $umsession->setProperty(UmScApp::SESSION_ARTICLE_LIST, $article_list); } $categories = DAO_KbCategory::getWhere(); $tpl->assign('categories', $categories); $cats = DAO_KbArticle::getCategoriesByArticleId($id); $breadcrumbs = array(); foreach ($cats as $cat_id) { if (!isset($breadcrumbs[$cat_id])) { $breadcrumbs[$cat_id] = array(); } $pid = $cat_id; while ($pid) { $breadcrumbs[$cat_id][] = $pid; $pid = $categories[$pid]->parent_id; } $breadcrumbs[$cat_id] = array_reverse($breadcrumbs[$cat_id]); // Remove any breadcrumbs not in this SC profile $pid = reset($breadcrumbs[$cat_id]); if (!isset($kb_roots[$pid])) { unset($breadcrumbs[$cat_id]); } } $tpl->assign('breadcrumbs', $breadcrumbs); $tpl->display("file:{$tpl_path}portal/sc/internal/kb/article.tpl"); break; default: case 'browse': @($root = intval(array_shift($stack))); $tpl->assign('root_id', $root); $categories = DAO_KbCategory::getWhere(); $tpl->assign('categories', $categories); $tree_map = DAO_KbCategory::getTreeMap(0); // Remove other top-level categories if (is_array($tree_map[0])) { foreach ($tree_map[0] as $child_id => $count) { if (!isset($kb_roots[$child_id])) { unset($tree_map[0][$child_id]); } } } // Remove empty categories if (is_array($tree_map[0])) { foreach ($tree_map as $node_id => $children) { foreach ($children as $child_id => $count) { if (empty($count)) { @($pid = $categories[$child_id]->parent_id); unset($tree_map[$pid][$child_id]); unset($tree_map[$child_id]); } } } } $tpl->assign('tree', $tree_map); // Breadcrumb // [TODO] API-ize inside Model_KbTree ? $breadcrumb = array(); $pid = $root; while (0 != $pid) { $breadcrumb[] = $pid; $pid = $categories[$pid]->parent_id; } $tpl->assign('breadcrumb', array_reverse($breadcrumb)); $tpl->assign('mid', @intval(ceil(count($tree_map[$root]) / 2))); // Articles if (!empty($root)) { list($articles, $count) = DAO_KbArticle::search(array(new DevblocksSearchCriteria(SearchFields_KbArticle::CATEGORY_ID, '=', $root), new DevblocksSearchCriteria(SearchFields_KbArticle::TOP_CATEGORY_ID, 'in', array_keys($kb_roots))), -1, 0, null, null, false); } $tpl->assign('articles', $articles); $tpl->display("file:{$tpl_path}portal/sc/internal/kb/index.tpl"); break; } break; case 'answers': $query = rawurldecode(array_shift($stack)); $tpl->assign('query', $query); $sFnrSources = DAO_CommunityToolProperty::get($this->getPortal(), UmScApp::PARAM_FNR_SOURCES, ''); $aFnrSources = !empty($sFnrSources) ? unserialize($sFnrSources) : array(); if (!empty($query)) { // [JAS]: If we've been customized with specific sources, use them $where = !empty($aFnrSources) ? sprintf("%s IN (%s)", DAO_FnrExternalResource::ID, implode(',', array_keys($aFnrSources))) : sprintf("%s IN (-1)", DAO_FnrExternalResource::ID); $resources = DAO_FnrExternalResource::getWhere($where); $feeds = Model_FnrExternalResource::searchResources($resources, $query); $tpl->assign('feeds', $feeds); $fields = array(DAO_FnrQuery::QUERY => $query, DAO_FnrQuery::CREATED => time(), DAO_FnrQuery::SOURCE => $this->getPortal(), DAO_FnrQuery::NO_MATCH => empty($feeds) ? 1 : 0); DAO_FnrQuery::create($fields); } // KB $sKbRoots = DAO_CommunityToolProperty::get($this->getPortal(), UmScApp::PARAM_KB_ROOTS, ''); $kb_roots = !empty($sKbRoots) ? unserialize($sKbRoots) : array(); list($articles, $count) = DAO_KbArticle::search(array(array(DevblocksSearchCriteria::GROUP_OR, new DevblocksSearchCriteria(SearchFields_KbArticle::TITLE, 'fulltext', $query), new DevblocksSearchCriteria(SearchFields_KbArticle::CONTENT, 'fulltext', $query)), new DevblocksSearchCriteria(SearchFields_KbArticle::TOP_CATEGORY_ID, 'in', array_keys($kb_roots))), 100, 0, null, null, true); $tpl->assign('articles', $articles); $tpl->display("file:{$tpl_path}portal/sc/internal/answers/index.tpl"); break; case 'contact': $response = array_shift($stack); $settings = CerberusSettings::getInstance(); $default_from = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM); $tpl->assign('default_from', $default_from); switch ($response) { case 'confirm': $tpl->assign('last_opened', $umsession->getProperty('support.write.last_opened', '')); $tpl->display("file:{$tpl_path}portal/sc/internal/contact/confirm.tpl"); break; default: case 'step1': $umsession->setProperty('support.write.last_error', null); case 'step2': $sFrom = $umsession->getProperty('support.write.last_from', ''); $sSubject = $umsession->getProperty('support.write.last_subject', ''); $sNature = $umsession->getProperty('support.write.last_nature', ''); $sContent = $umsession->getProperty('support.write.last_content', ''); // $aLastFollowupQ = $umsession->getProperty('support.write.last_followup_q',''); $aLastFollowupA = $umsession->getProperty('support.write.last_followup_a', ''); $sError = $umsession->getProperty('support.write.last_error', ''); $tpl->assign('last_from', $sFrom); $tpl->assign('last_subject', $sSubject); $tpl->assign('last_nature', $sNature); $tpl->assign('last_content', $sContent); // $tpl->assign('last_followup_q', $aLastFollowupQ); $tpl->assign('last_followup_a', $aLastFollowupA); $tpl->assign('last_error', $sError); $sDispatch = DAO_CommunityToolProperty::get($this->getPortal(), UmScApp::PARAM_DISPATCH, ''); // $dispatch = !empty($sDispatch) ? (is_array($sDispatch) ? unserialize($sDispatch): array($sDispatch)) : array(); $dispatch = !empty($sDispatch) ? unserialize($sDispatch) : array(); $tpl->assign('dispatch', $dispatch); switch ($response) { default: // If there's only one situation, skip to step2 if (1 == count($dispatch)) { @($sNature = md5(key($dispatch))); $umsession->setProperty('support.write.last_nature', $sNature); reset($dispatch); } else { $tpl->display("file:{$tpl_path}portal/sc/internal/contact/step1.tpl"); break; } case 'step2': // Cache along with answers? if (is_array($dispatch)) { foreach ($dispatch as $k => $v) { if (md5($k) == $sNature) { $umsession->setProperty('support.write.last_nature_string', $k); $tpl->assign('situation', $k); $tpl->assign('situation_params', $v); break; } } } $ticket_fields = DAO_CustomField::getBySource('cerberusweb.fields.source.ticket'); $tpl->assign('ticket_fields', $ticket_fields); $tpl->display("file:{$tpl_path}portal/sc/internal/contact/step2.tpl"); break; } break; } break; // $tpl->display("file:${tpl_path}portal/sc/internal/contact/index.tpl"); // break; // $tpl->display("file:${tpl_path}portal/sc/internal/contact/index.tpl"); // break; case 'history': if (!$this->allow_logins || empty($active_user)) { break; } $mask = array_shift($stack); if (empty($mask)) { list($open_tickets) = DAO_Ticket::search(array(), array(new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_FIRST_WROTE_ID, '=', $active_user->id), new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_CLOSED, '=', 0)), -1, 0, SearchFields_Ticket::TICKET_UPDATED_DATE, false, false); $tpl->assign('open_tickets', $open_tickets); list($closed_tickets) = DAO_Ticket::search(array(), array(new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_FIRST_WROTE_ID, '=', $active_user->id), new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_CLOSED, '=', 1)), -1, 0, SearchFields_Ticket::TICKET_UPDATED_DATE, false, false); $tpl->assign('closed_tickets', $closed_tickets); $tpl->display("file:{$tpl_path}portal/sc/internal/history/index.tpl"); } else { // Secure retrieval (address + mask) list($tickets) = DAO_Ticket::search(array(), array(new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_MASK, '=', $mask), new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_FIRST_WROTE_ID, '=', $active_user->id)), 1, 0, null, null, false); $ticket = array_shift($tickets); // Security check (mask compare) if (0 == strcasecmp($ticket[SearchFields_Ticket::TICKET_MASK], $mask)) { $messages = DAO_Ticket::getMessagesByTicket($ticket[SearchFields_Ticket::TICKET_ID]); $messages = array_reverse($messages, true); $tpl->assign('ticket', $ticket); $tpl->assign('messages', $messages); $tpl->display("file:{$tpl_path}portal/sc/internal/history/display.tpl"); } } break; case 'register': if (!$this->allow_logins) { break; } @($step = array_shift($stack)); switch ($step) { case 'forgot': $tpl->display("file:{$tpl_path}portal/sc/internal/register/forgot.tpl"); break; case 'forgot2': $tpl->display("file:{$tpl_path}portal/sc/internal/register/forgot_confirm.tpl"); break; case 'confirm': $tpl->display("file:{$tpl_path}portal/sc/internal/register/confirm.tpl"); break; default: $tpl->display("file:{$tpl_path}portal/sc/internal/register/index.tpl"); break; } break; } // print_r($response); }
static function calculateTicketSpamProbability($ticket_id, $readonly = false) { // pull up text of first ticket message $messages = DAO_Ticket::getMessagesByTicket($ticket_id); $first_message = array_shift($messages); $ticket = DAO_Ticket::getTicket($ticket_id); if (empty($ticket) || empty($first_message) || !$first_message instanceof CerberusMessage) { return FALSE; } // Pass text to analyze() to get back interesting words $content = ''; if (!empty($ticket->subject)) { // SplitCamelCapsSubjects $hits = preg_split("{(?<=[a-z])(?=[A-Z])}x", $ticket->subject); if (is_array($hits) && !empty($hits)) { $content .= implode(' ', $hits); } } $content .= ' ' . $first_message->getContent(); // Only check the first 15000 characters for spam, rounded to a sentence if (strlen($content) > self::MAX_BODY_LENGTH) { $content = substr($content, 0, strrpos(substr($content, 0, self::MAX_BODY_LENGTH), ' ')); } $words = self::processText($content); $out = self::_calculateSpamProbability($words); // Make a word list $rawwords = array(); foreach ($out['words'] as $k => $v) { /* @var $v CerberusBayesWord */ $rawwords[] = $v->word; } // Cache probability if (!$readonly) { $fields = array(DAO_Ticket::SPAM_SCORE => $out['probability'], DAO_Ticket::INTERESTING_WORDS => substr(implode(',', array_reverse($rawwords)), 0, 255)); DAO_Ticket::updateTicket($ticket_id, $fields); } return $out; }
private function _getListAction($path) { @($ticket_id = DevblocksPlatform::importGPC($_REQUEST['ticket_id'], 'integer', 0)); if (0 == $ticket_id) { $this->_error("Ticket ID was not provided."); } $messages = DAO_Ticket::getMessagesByTicket($ticket_id); $xml_out = new SimpleXMLElement("<messages></messages>"); foreach ($messages as $message) { $message_xml = $xml_out->addChild('message'); $message_xml->addChild('id', $message->id); $message_xml->addChild('ticket_id', $message->ticket_id); $message_xml->addChild('created_date', $message->created_date); $message_xml->addChild('address_id', $message->address_id); $message_xml->addChild('is_outgoing', $message->is_outgoing); $message_xml->addChild('worker_id', $message->worker_id); } $this->_render($xml_out->asXML()); }
function getMessages() { $messages = DAO_Ticket::getMessagesByTicket($this->id); return $messages; }
function showPreviewAction() { @($tid = DevblocksPlatform::importGPC($_REQUEST['tid'], 'integer', 0)); @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'], 'string', '')); $tpl = DevblocksPlatform::getTemplateService(); $tpl_path = $this->_TPL_PATH; $tpl->assign('path', $tpl_path); $tpl->assign('view_id', $view_id); if (null != ($ticket = DAO_Ticket::getTicket($tid))) { /* @var $ticket CerberusTicket */ $tpl->assign('ticket', $ticket); } if (null != ($messages = DAO_Ticket::getMessagesByTicket($tid))) { if (!empty($messages)) { @($last = array_pop($messages)); @($content = DAO_MessageContent::get($last->id)); $tpl->assign('message', $last); $tpl->assign('content', $content); } } $teams = DAO_Group::getAll(); $tpl->assign('teams', $teams); $team_categories = DAO_Bucket::getTeams(); $tpl->assign('team_categories', $team_categories); $workers = DAO_Worker::getAllActive(); $tpl->assign('workers', $workers); // Custom fields $custom_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Ticket::ID); $tpl->assign('custom_fields', $custom_fields); $custom_field_values = DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_Ticket::ID, $ticket->id); if (isset($custom_field_values[$ticket->id])) { $tpl->assign('custom_field_values', $custom_field_values[$ticket->id]); } // Display $tpl->display('file:' . $this->_TPL_PATH . 'tickets/rpc/preview_panel.tpl'); }
function doReplyAction() { @($mask = DevblocksPlatform::importGPC($_REQUEST['mask'], 'string', '')); @($content = DevblocksPlatform::importGPC($_REQUEST['content'], 'string', '')); $umsession = UmPortalHelper::getSession(); $active_user = $umsession->getProperty('sc_login', null); // Secure retrieval (address + mask) list($tickets) = DAO_Ticket::search(array(), array(new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_MASK, '=', $mask), new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_FIRST_WROTE_ID, '=', $active_user->id)), 1, 0, null, null, false); $ticket = array_shift($tickets); $messages = DAO_Ticket::getMessagesByTicket($ticket[SearchFields_Ticket::TICKET_ID]); $last_message = array_pop($messages); /* @var $last_message CerberusMessage */ $last_message_headers = $last_message->getHeaders(); unset($messages); // Helpdesk settings $settings = CerberusSettings::getInstance(); $global_from = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM, null); // Ticket group settings $group_id = $ticket[SearchFields_Ticket::TICKET_TEAM_ID]; @($group_from = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_REPLY_FROM, '')); // Headers $to = !empty($group_from) ? $group_from : $global_from; @($in_reply_to = $last_message_headers['message-id']); @($message_id = CerberusApplication::generateMessageId()); $message = new CerberusParserMessage(); $message->headers['from'] = $active_user->email; $message->headers['to'] = $to; $message->headers['date'] = gmdate('r'); $message->headers['subject'] = 'Re: ' . $ticket[SearchFields_Ticket::TICKET_SUBJECT]; $message->headers['message-id'] = $message_id; $message->headers['in-reply-to'] = $in_reply_to; $message->body = sprintf("%s", $content); CerberusParser::parseMessage($message, array('no_autoreply' => true)); DevblocksPlatform::setHttpResponse(new DevblocksHttpResponse(array('portal', UmPortalHelper::getCode(), 'history', $ticket[SearchFields_Ticket::TICKET_MASK]))); }
private function _sendForwards($event, $is_inbound) { @($ticket_id = $event->params['ticket_id']); @($send_worker_id = $event->params['worker_id']); $url_writer = DevblocksPlatform::getUrlService(); $ticket = DAO_Ticket::getTicket($ticket_id); // (Action) Forward Email To: // Sanitize and combine all the destination addresses $next_worker = DAO_Worker::getAgent($ticket->next_worker_id); $notify_emails = $next_worker->email; if (empty($notify_emails)) { return; } // [TODO] This could be more efficient $messages = DAO_Ticket::getMessagesByTicket($ticket_id); $message = end($messages); // last message unset($messages); $headers = $message->getHeaders(); // The whole flipping Swift section needs wrapped to catch exceptions try { $settings = CerberusSettings::getInstance(); $reply_to = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM, ''); // See if we need a group-specific reply-to if (!empty($ticket->team_id)) { @($group_from = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_FROM, '')); if (!empty($group_from)) { $reply_to = $group_from; } } $sender = DAO_Address::get($message->address_id); $sender_email = strtolower($sender->email); $sender_split = explode('@', $sender_email); if (!is_array($sender_split) || count($sender_split) != 2) { return; } // If return-path is blank if (isset($headers['return-path']) && $headers['return-path'] == '<>') { return; } // Ignore bounces if ($sender_split[0] == "postmaster" || $sender_split[0] == "mailer-daemon") { return; } // Ignore autoresponses autoresponses if (isset($headers['auto-submitted']) && $headers['auto-submitted'] != 'no') { return; } // Attachments $attachments = $message->getAttachments(); $mime_attachments = array(); if (is_array($attachments)) { foreach ($attachments as $attachment) { if (0 == strcasecmp($attachment->display_name, 'original_message.html')) { continue; } $attachment_path = APP_STORAGE_PATH . '/attachments/'; // [TODO] This is highly redundant in the codebase if (!file_exists($attachment_path . $attachment->filepath)) { continue; } $attach = Swift_Attachment::fromPath($attachment_path . $attachment->filepath); if (!empty($attachment->display_name)) { $attach->setFilename($attachment->display_name); } $mime_attachments[] = $attach; } } // Send copies $mail_service = DevblocksPlatform::getMailService(); $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults()); $mail = $mail_service->createMessage(); /* @var $mail Swift_Message */ $mail->setTo(array($notify_emails)); $mail->setFrom(array($sender->email)); $mail->setReplyTo($reply_to); $mail->setReturnPath($reply_to); $mail->setSubject(sprintf("[RW: %s #%s]: %s", $is_inbound ? 'inbound' : 'outbound', $ticket->mask, $ticket->subject)); $hdrs = $mail->getHeaders(); if (null !== @($msgid = $headers['message-id'])) { $hdrs->addTextHeader('Message-Id', $msgid); } if (null !== @($in_reply_to = $headers['in-reply-to'])) { $hdrs->addTextHeader('References', $in_reply_to); $hdrs->addTextHeader('In-Reply-To', $in_reply_to); } $hdrs->addTextHeader('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')'); $hdrs->addTextHeader('Precedence', 'List'); $hdrs->addTextHeader('Auto-Submitted', 'auto-generated'); $mail->setBody($message->getContent()); // Send message attachments with watcher if (is_array($mime_attachments)) { foreach ($mime_attachments as $mime_attachment) { $mail->attach($mime_attachment); } } $result = $mailer->send($mail); } catch (Exception $e) { if (!empty($message_id)) { $fields = array(DAO_MessageNote::MESSAGE_ID => $message_id, DAO_MessageNote::CREATED => time(), DAO_MessageNote::WORKER_ID => 0, DAO_MessageNote::CONTENT => 'Exception thrown while sending watcher email: ' . $e->getMessage(), DAO_MessageNote::TYPE => Model_MessageNote::TYPE_ERROR); DAO_MessageNote::create($fields); } } }