function writeResponse(DevblocksHttpResponse $response) { $tpl = DevblocksPlatform::getTemplateService(); $tpl_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/templates/'; $umsession = UmPortalHelper::getSession(); $active_user = $umsession->getProperty('sc_login', null); $address = DAO_Address::get($active_user->id); $tpl->assign('address', $address); $tpl->display("devblocks:usermeet.core:support_center/account/index.tpl:portal_" . UmPortalHelper::getCode()); }
function writeResponse(DevblocksHttpResponse $response) { $tpl = DevblocksPlatform::getTemplateService(); $tpl_path = dirname(dirname(dirname(dirname(__FILE__)))) . '/templates/'; $umsession = UmPortalHelper::getSession(); $active_user = $umsession->getProperty('sc_login', null); $address = DAO_Address::get($active_user->id); $tpl->assign('address', $address); $tpl->display("file:" . $tpl_path . "portal/sc/module/account/index.tpl"); }
function handleRequest(DevblocksHttpRequest $request) { $worker = CerberusApplication::getActiveWorker(); if (empty($worker)) { return; } $stack = $request->path; array_shift($stack); // print @($object = strtolower(array_shift($stack))); // ticket|message|etc $tpl = DevblocksPlatform::getTemplateService(); $tpl->assign('path', $this->_TPL_PATH); $settings = DevblocksPlatform::getPluginSettingsService(); $tpl->assign('settings', $settings); $translate = DevblocksPlatform::getTranslationService(); $tpl->assign('translate', $translate); $teams = DAO_Group::getAll(); $tpl->assign('teams', $teams); $buckets = DAO_Bucket::getAll(); $tpl->assign('buckets', $buckets); $workers = DAO_Worker::getAll(); $tpl->assign('workers', $workers); // Security $active_worker = CerberusApplication::getActiveWorker(); $active_worker_memberships = $active_worker->getMemberships(); // [TODO] Make this pluggable // Subcontroller switch ($object) { case 'ticket': @($id = array_shift($stack)); @($ticket = is_numeric($id) ? DAO_Ticket::getTicket($id) : DAO_Ticket::getTicketByMask($id)); $convo_timeline = array(); $messages = $ticket->getMessages(); 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); } @($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($ticket->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); } } ksort($convo_timeline); $tpl->assign('convo_timeline', $convo_timeline); // Comment parent addresses $comment_addresses = array(); foreach ($comments as $comment) { /* @var $comment Model_TicketComment */ $address_id = intval($comment->address_id); if (!isset($comment_addresses[$address_id])) { $address = DAO_Address::get($address_id); $comment_addresses[$address_id] = $address; } } $tpl->assign('comment_addresses', $comment_addresses); // Message Notes $notes = DAO_MessageNote::getByTicketId($ticket->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); // Make sure we're allowed to view this ticket or message if (!isset($active_worker_memberships[$ticket->team_id])) { echo "<H1>" . $translate->_('common.access_denied') . "</H1>"; return; } $tpl->assign('ticket', $ticket); $tpl->display('file:' . $this->_TPL_PATH . 'print/ticket.tpl'); break; case 'message': @($id = array_shift($stack)); @($message = DAO_Ticket::getMessage($id)); @($ticket = DAO_Ticket::getTicket($message->ticket_id)); // Make sure we're allowed to view this ticket or message if (!isset($active_worker_memberships[$ticket->team_id])) { echo "<H1>" . $translate->_('common.access_denied') . "</H1>"; return; } // Message Notes $notes = DAO_MessageNote::getByTicketId($ticket->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); $tpl->assign('message', $message); $tpl->assign('ticket', $ticket); $tpl->display('file:' . $this->_TPL_PATH . 'print/message.tpl'); break; } }
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); }
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'); }
function showAddressTicketsAction() { @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); @($closed = DevblocksPlatform::importGPC($_REQUEST['closed'], 'integer', 0)); if (null == ($address = DAO_Address::get($id))) { return; } if (null == ($search_view = C4_AbstractViewLoader::getView(CerberusApplication::VIEW_SEARCH))) { $search_view = C4_TicketView::createSearchView(); } $search_view->params = array(SearchFields_Ticket::TICKET_CLOSED => new DevblocksSearchCriteria(SearchFields_Ticket::TICKET_CLOSED, '=', $closed), SearchFields_Ticket::REQUESTER_ADDRESS => new DevblocksSearchCriteria(SearchFields_Ticket::REQUESTER_ADDRESS, '=', $address->email)); $search_view->renderPage = 0; C4_AbstractViewLoader::setView(CerberusApplication::VIEW_SEARCH, $search_view); DevblocksPlatform::redirect(new DevblocksHttpResponse(array('tickets', 'search'))); }
function showEntryAction() { @($active_worker = CerberusApplication::getActiveWorker()); @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'], 'string', '')); $tpl = DevblocksPlatform::getTemplateService(); $tpl_path = dirname(dirname(__FILE__)) . '/templates/'; $tpl->assign('path', $this->plugin_path . '/templates/'); $tpl->assign('view_id', $view_id); // Editing @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); // Creating @($msg_id = DevblocksPlatform::importGPC($_REQUEST['msg_id'], 'integer', 0)); @($quote = DevblocksPlatform::importGPC($_REQUEST['quote'], 'string', '')); @($url = DevblocksPlatform::importGPC($_REQUEST['url'], 'string', '')); @($source_ext_id = DevblocksPlatform::importGPC($_REQUEST['source_ext_id'], 'string', '')); @($source_id = DevblocksPlatform::importGPC($_REQUEST['source_id'], 'integer', 0)); /* * This treats procedurally created model objects * the same as existing objects */ if (empty($id)) { $model = new Model_FeedbackEntry(); if (!empty($msg_id)) { if (null != ($message = DAO_Ticket::getMessage($msg_id))) { $model->id = 0; $model->log_date = time(); $model->quote_address_id = $message->address_id; $model->quote_mood = 0; $model->quote_text = $quote; $model->worker_id = $active_worker->id; $model->source_url = $url; $tpl->assign('model', $model); } } } elseif (!empty($id)) { // Were we given a model ID to load? if (null != ($model = DAO_FeedbackEntry::get($id))) { $tpl->assign('model', $model); } } // Author (if not anonymous) if (!empty($model->quote_address_id)) { if (null != ($address = DAO_Address::get($model->quote_address_id))) { $tpl->assign('address', $address); } } if (!empty($source_ext_id)) { $tpl->assign('source_extension_id', $source_ext_id); $tpl->assign('source_id', $source_id); } // Custom fields $custom_fields = DAO_CustomField::getBySource(ChCustomFieldSource_FeedbackEntry::ID); $tpl->assign('custom_fields', $custom_fields); $custom_field_values = DAO_CustomFieldValue::getValuesBySourceIds(ChCustomFieldSource_FeedbackEntry::ID, $id); if (isset($custom_field_values[$id])) { $tpl->assign('custom_field_values', $custom_field_values[$id]); } $types = Model_CustomField::getTypes(); $tpl->assign('types', $types); $tpl->display('file:' . $this->plugin_path . '/templates/feedback/ajax/feedback_entry_panel.tpl'); }
function getStopTimerPanelAction() { $total_secs = $this->_stopTimer(); $this->_stopTimer(); $object = new Model_TimeTrackingEntry(); $object->id = 0; // Time // $tpl->assign('total_secs', $total_secs); // $tpl->assign('total_mins', ceil($total_secs/60)); $object->time_actual_mins = ceil($total_secs / 60); // Source @($source_ext_id = strtolower($_SESSION['timetracking_source_ext_id'])); @($source_id = intval($_SESSION['timetracking_source_id'])); $object->source_extension_id = $source_ext_id; $object->source_id = $source_id; // $tpl->assign('source_ext_id', $source_ext_id); // $tpl->assign('source_id', $source_id); switch ($source_ext_id) { // Ticket case 'timetracking.source.ticket': if (null != ($ticket = DAO_Ticket::getTicket($source_id))) { // Timeslip Responsible Party if (null != ($address = DAO_Address::get($ticket->first_wrote_address_id))) { // $tpl->assign('performed_for', $address->email); // Timeslip Org if (!empty($address->contact_org_id)) { // && null != ($org = DAO_ContactOrg::get($address->contact_org_id))) { // $tpl->assign('org', $org->name); $object->debit_org_id = $address->contact_org_id; } } // Timeslip reference // $tpl->assign('reference', sprintf("Ticket #%s", // $ticket->mask // //((strlen($ticket->subject)>45) ? (substr($ticket->subject,0,45).'...') : $ticket->subject) // )); // Timeslip note $object->notes = sprintf("Ticket #%s ", $ticket->mask); // $tpl->assign('note', sprintf("Replied to %s", // $ticket->mask, // (!empty($address->email) ? $address->email : '') // )); } break; } $this->showEntryAction($object); }
private function _putIdAction($path) { $xmlstr = $this->getPayload(); $xml_in = new SimpleXMLElement($xmlstr); $in_id = array_shift($path); if (empty($in_id)) { $this->_error("ID was not provided."); } if (null == ($address = DAO_Address::get($in_id))) { $this->_error("ID not valid."); } $fields = array(); $flds = DAO_Address::getFields(); unset($flds[DAO_Address::ID]); foreach ($flds as $idx => $f) { $idx_name = $this->translate($idx, true); if ($idx_name == null) { continue; } @($value = DevblocksPlatform::importGPC($xml_in->{$idx_name}, 'string')); if ($this->isValid($idx_name, $value)) { $fields[$idx] = $value; } } // [TODO] This referential integrity should really be up to DAO if (!empty($fields[DAO_Address::CONTACT_ORG_ID])) { $in_contact_org_id = intval($fields[DAO_Address::CONTACT_ORG_ID]); if (null == ($contact_org = DAO_ContactOrg::get($in_contact_org_id))) { unset($fields[DAO_Address::CONTACT_ORG_ID]); } } if (!empty($fields)) { DAO_Address::update($address->id, $fields); } // update password if requested @($password = DevblocksPlatform::importGPC($xml_in->password, 'string', '')); if (!empty($password)) { DAO_AddressAuth::update($in_id, array(DAO_AddressAuth::PASS => md5($password))); } // send confirmation if requested @($confirmation_link = DevblocksPlatform::importGPC($xml_in->send_confirmation, 'string', '')); if (!empty($confirmation_link)) { $this->_sendConfirmation($address->email, $confirmation_link); } $this->_getIdAction(array($address->id)); }
/** * Enter description here... * * @param unknown_type $email * @param unknown_type $create_if_null * @return Model_Address */ static function lookupAddress($email, $create_if_null = false) { $db = DevblocksPlatform::getDatabaseService(); $address = null; $email = trim(strtolower($email)); $addresses = self::getWhere(sprintf("email = %s", $db->qstr($email))); if (is_array($addresses) && !empty($addresses)) { $address = array_shift($addresses); } elseif ($create_if_null) { $fields = array(self::EMAIL => $email); $id = DAO_Address::create($fields); $address = DAO_Address::get($id); } return $address; }
/** * @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; }
private function _sendForwards($event, $is_inbound) { @($ticket_id = $event->params['ticket_id']); @($message_id = $event->params['message_id']); @($send_worker_id = $event->params['worker_id']); $ticket = DAO_Ticket::getTicket($ticket_id); $helpdesk_senders = CerberusApplication::getHelpdeskSenders(); $workers = DAO_Worker::getAllActive(); // [JAS]: Don't send obvious spam to watchers. if ($ticket->spam_score >= 0.9) { return true; } @($notifications = DAO_WorkerMailForward::getWhere(sprintf("%s = %d", DAO_WorkerMailForward::GROUP_ID, $ticket->team_id))); // Bail out early if we have no forwards for this group if (empty($notifications)) { return; } $message = DAO_Ticket::getMessage($message_id); $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[1] == "postmaster" || $sender_split[1] == "mailer-daemon") { return; } // Ignore autoresponses autoresponses if (isset($headers['auto-submitted']) && $headers['auto-submitted'] != 'no') { return; } // Headers //========== // Build mailing list $send_to = array(); foreach ($notifications as $n) { /* @var $n Model_WorkerMailForward */ if (!isset($n->group_id) || !isset($n->bucket_id)) { continue; } // if worker no longer exists or is disabled if (!isset($workers[$n->worker_id])) { continue; } // Don't allow a worker to usurp a helpdesk address if (isset($helpdesk_senders[$n->email])) { continue; } if ($n->group_id == $ticket->team_id && ($n->bucket_id == -1 || $n->bucket_id == $ticket->category_id)) { // Event checking if ($is_inbound && ($n->event == 'i' || $n->event == 'io') || !$is_inbound && ($n->event == 'o' || $n->event == 'io') || $is_inbound && $n->event == 'r' && $ticket->next_worker_id == $n->worker_id) { $send_to[$n->email] = true; } } } // 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; } $file =& new Swift_File($attachment_path . $attachment->filepath); $mime_attachments[] =& new Swift_Message_Attachment($file, $attachment->display_name, $attachment->mime_type); } } // Send copies if (is_array($send_to) && !empty($send_to)) { $mail_service = DevblocksPlatform::getMailService(); $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults()); foreach ($send_to as $to => $bool) { // Proxy the message $rcpt_to = new Swift_RecipientList(); $a_rcpt_to = array(); $mail_from = new Swift_Address($sender->email); $rcpt_to->addTo($to); $a_rcpt_to = new Swift_Address($to); $mail = $mail_service->createMessage(); /* @var $mail Swift_Message */ $mail->setTo($a_rcpt_to); $mail->setFrom($mail_from); $mail->setReplyTo($reply_to); $mail->setReturnPath($reply_to); $mail->setSubject(sprintf("[%s #%s]: %s", $is_inbound ? 'inbound' : 'outbound', $ticket->mask, $ticket->subject)); if (false !== @($msgid = $headers['message-id'])) { $mail->headers->set('Message-Id', $msgid); } if (false !== @($in_reply_to = $headers['in-reply-to'])) { $mail->headers->set('References', $in_reply_to); $mail->headers->set('In-Reply-To', $in_reply_to); } $mail->headers->set('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')'); $mail->headers->set('Precedence', 'List'); $mail->headers->set('Auto-Submitted', 'auto-generated'); $mail->attach(new Swift_Message_Part($message->getContent(), 'text/plain', 'base64', LANG_CHARSET_CODE)); // Send message attachments with watcher if (is_array($mime_attachments)) { foreach ($mime_attachments as $mime_attachment) { $mail->attach($mime_attachment); } } $mailer->send($mail, $rcpt_to, $mail_from); } } } catch (Exception $e) { $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); } }
private function newTicketComment($event) { DevblocksPlatform::getExtensions('cerberusweb.ticket.tab', true); // ticket_comment.id @($comment_id = $event->params['comment_id']); // Event context @($context = $event->params['context']); // ticket.id if context == ticket. @(${$ticket_id} = $event->params['context_id']); @($address_id = $event->params['address_id']); // text of actual comment. @($comment_text = $event->params['comment']); if (CerberusContexts::CONTEXT_TICKET != $context) { return; } if (empty($ticket_id) || empty($address_id) || empty($comment_text)) { return; } $settings = DevblocksPlatform::getPluginSettingsService(); $al_merge_enabled = intval($settings->get('cerb5blog.last_action_and_audit_log', 'al_merge_enabled', 0)); if (class_exists('DAO_TicketAuditLog', true)) { $al_comment_enabled = intval($settings->get('cerb5blog.last_action_and_audit_log', 'al_comment_enabled', 0)); if ($al_comment_enabled) { @($address = DAO_Address::get($address_id)); @($worker_id = DAO_Worker::lookupAgentEmail($address->email)); $fields = array(DAO_TicketAuditLog::TICKET_ID => $ticket_id, DAO_TicketAuditLog::WORKER_ID => $worker_id, DAO_TicketAuditLog::CHANGE_DATE => time(), DAO_TicketAuditLog::CHANGE_FIELD => "cerb5blog.last_action_and_audit_log.type.comment", DAO_TicketAuditLog::CHANGE_VALUE => substr($comment_text, 0, 128)); $log_id = DAO_TicketAuditLog::create($fields); unset($fields); } } $uf_comment_enabled = intval($settings->get('cerb5blog.last_action_and_audit_log', 'uf_comment_enabled', 0)); if ($uf_comment_enabled) { $change_fields[DAO_Ticket::UPDATED_DATE] = time(); DAO_Ticket::update($ticket_id, $change_fields); unset($change_fields); } }
static function sendTicketMessage($properties = array()) { $settings = DevblocksPlatform::getPluginSettingsService(); $helpdesk_senders = CerberusApplication::getHelpdeskSenders(); @($from_addy = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_FROM, $_SERVER['SERVER_ADMIN'])); @($from_personal = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_PERSONAL, '')); // [TODO] If we still don't have a $from_addy we need a graceful failure. /* * [TODO] Move these into constants? 'message_id' -----'ticket_id' 'subject' 'to' 'cc' 'bcc' 'content' 'files' 'closed' 'ticket_reopen' 'unlock_date' 'bucket_id' 'agent_id', 'is_autoreply', 'dont_send', 'dont_save_copy' */ $mail_succeeded = true; try { // objects $mail_service = DevblocksPlatform::getMailService(); $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults()); $mail = $mail_service->createMessage(); // properties @($reply_message_id = $properties['message_id']); @($content = $properties['content']); @($files = $properties['files']); @($forward_files = $properties['forward_files']); @($worker_id = $properties['agent_id']); @($subject = $properties['subject']); $message = DAO_Ticket::getMessage($reply_message_id); $message_headers = DAO_MessageHeader::getAll($reply_message_id); $ticket_id = $message->ticket_id; $ticket = DAO_Ticket::getTicket($ticket_id); // [TODO] Check that message|ticket isn't NULL // If this ticket isn't spam trained and our outgoing message isn't an autoreply if ($ticket->spam_training == CerberusTicketSpamTraining::BLANK && (!isset($properties['is_autoreply']) || !$properties['is_autoreply'])) { CerberusBayes::markTicketAsNotSpam($ticket_id); } // Allow teams to override the default from/personal @($group_reply = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_FROM, '')); @($group_personal = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_PERSONAL, '')); @($group_personal_with_worker = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_PERSONAL_WITH_WORKER, 0)); if (!empty($group_reply)) { $from_addy = $group_reply; } if (!empty($group_personal)) { $from_personal = $group_personal; } // Prefix the worker name on the personal line? if (!empty($group_personal_with_worker) && null != ($reply_worker = DAO_Worker::getAgent($worker_id))) { $from_personal = $reply_worker->getName() . (!empty($from_personal) ? ', ' . $from_personal : ""); } // Headers $mail->setFrom(array($from_addy => $from_personal)); $mail->generateId(); $headers = $mail->getHeaders(); $headers->addTextHeader('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')'); // Subject if (empty($subject)) { $subject = $ticket->subject; } if (!empty($properties['to'])) { // forward $mail->setSubject($subject); } else { // reply @($group_has_subject = intval(DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_SUBJECT_HAS_MASK, 0))); @($group_subject_prefix = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_SUBJECT_PREFIX, '')); $prefix = sprintf("[%s#%s] ", !empty($group_subject_prefix) ? $group_subject_prefix . ' ' : '', $ticket->mask); $mail->setSubject(sprintf('Re: %s%s', $group_has_subject ? $prefix : '', $subject)); } // References if (!empty($message) && false !== @($in_reply_to = $message_headers['message-id'])) { $headers->addTextHeader('References', $in_reply_to); $headers->addTextHeader('In-Reply-To', $in_reply_to); } // Auto-reply handling (RFC-3834 compliant) if (isset($properties['is_autoreply']) && $properties['is_autoreply']) { $headers->addTextHeader('Auto-Submitted', 'auto-replied'); if (null == ($first_address = DAO_Address::get($ticket->first_wrote_address_id))) { return; } // Don't send e-mail to ourselves if (isset($helpdesk_senders[$first_address->email])) { return; } // Make sure we haven't mailed this address an autoreply within 5 minutes if ($first_address->last_autoreply > 0 && $first_address->last_autoreply > time() - 300) { return; } $first_email = strtolower($first_address->email); $first_split = explode('@', $first_email); if (!is_array($first_split) || count($first_split) != 2) { return; } // If return-path is blank if (isset($message_headers['return-path']) && $message_headers['return-path'] == '<>') { return; } // Ignore bounces if ($first_split[0] == "postmaster" || $first_split[0] == "mailer-daemon") { return; } // Ignore autoresponses to autoresponses if (isset($message_headers['auto-submitted']) && $message_headers['auto-submitted'] != 'no') { return; } if (isset($message_headers['precedence']) && ($message_headers['precedence'] == 'list' || $message_headers['precedence'] == 'junk' || ($message_headers['precedence'] = 'bulk'))) { return; } // Set the auto-reply date for this address to right now DAO_Address::update($ticket->first_wrote_address_id, array(DAO_Address::LAST_AUTOREPLY => time())); // Auto-reply just to the initial requester $mail->addTo($first_address->email); // Not an auto-reply } else { // Forwards if (!empty($properties['to'])) { $aTo = DevblocksPlatform::parseCsvString(str_replace(';', ',', $properties['to'])); if (is_array($aTo)) { foreach ($aTo as $to_addy) { $mail->addTo($to_addy); } } // Replies } else { // Recipients $requesters = DAO_Ticket::getRequestersByTicket($ticket_id); if (is_array($requesters)) { foreach ($requesters as $requester) { /* @var $requester Model_Address */ $mail->addTo($requester->email); } } } // Ccs if (!empty($properties['cc'])) { $aCc = DevblocksPlatform::parseCsvString(str_replace(';', ',', $properties['cc'])); $mail->setCc($aCc); } // Bccs if (!empty($properties['bcc'])) { $aBcc = DevblocksPlatform::parseCsvString(str_replace(';', ',', $properties['bcc'])); $mail->setBcc($aBcc); } } /* * [IMPORTANT -- Yes, this is simply a line in the sand.] * You're welcome to modify the code to meet your needs, but please respect * our licensing. Buy a legitimate copy to help support the project! * http://www.cerberusweb.com/ */ $license = CerberusLicense::getInstance(); if (empty($license) || @empty($license['serial'])) { $content .= base64_decode("DQoNCi0tLQ0KQ29tYmF0IHNwYW0gYW5kIGltcHJvdmUgcmVzc" . "G9uc2UgdGltZXMgd2l0aCBDZXJiZXJ1cyBIZWxwZGVzayA0LjAhDQpodHRwOi8vd3d3LmNlc" . "mJlcnVzd2ViLmNvbS8NCg"); } // Body $mail->setBody($content); // Mime Attachments if (is_array($files) && !empty($files)) { foreach ($files['tmp_name'] as $idx => $file) { if (empty($file) || empty($files['name'][$idx])) { continue; } $mail->attach(Swift_Attachment::fromPath($file)->setFilename($files['name'][$idx])); } } // Forward Attachments if (!empty($forward_files) && is_array($forward_files)) { $attachments_path = APP_STORAGE_PATH . '/attachments/'; foreach ($forward_files as $file_id) { $attachment = DAO_Attachment::get($file_id); $attachment_path = $attachments_path . $attachment->filepath; $mail->attach(Swift_Attachment::fromPath($attachment_path)->setFilename($attachment->display_name)); } } if (!DEMO_MODE) { // If we're not supposed to send if (isset($properties['dont_send']) && $properties['dont_send']) { // ...do nothing } else { // otherwise send if (!$mailer->send($mail)) { $mail_succeeded = false; throw new Exception('Mail not sent.'); } } } } catch (Exception $e) { // tag failure, so we can add a note to the message later $mail_succeeded = false; } // Handle post-mail actions $change_fields = array(); $fromAddressInst = CerberusApplication::hashLookupAddress($from_addy, true); $fromAddressId = $fromAddressInst->id; if ((!isset($properties['dont_keep_copy']) || !$properties['dont_keep_copy']) && (!isset($properties['is_autoreply']) || !$properties['is_autoreply'])) { $change_fields[DAO_Ticket::LAST_WROTE_ID] = $fromAddressId; $change_fields[DAO_Ticket::UPDATED_DATE] = time(); if (!empty($worker_id)) { $change_fields[DAO_Ticket::LAST_WORKER_ID] = $worker_id; $change_fields[DAO_Ticket::LAST_ACTION_CODE] = CerberusTicketActionCode::TICKET_WORKER_REPLY; } // Only change the subject if not forwarding if (!empty($subject) && empty($properties['to'])) { $change_fields[DAO_Ticket::SUBJECT] = $subject; } $fields = array(DAO_Message::TICKET_ID => $ticket_id, DAO_Message::CREATED_DATE => time(), DAO_Message::ADDRESS_ID => $fromAddressId, DAO_Message::IS_OUTGOING => 1, DAO_Message::WORKER_ID => !empty($worker_id) ? $worker_id : 0); $message_id = DAO_Message::create($fields); // Content DAO_MessageContent::create($message_id, $content); $headers = $mail->getHeaders(); // Headers foreach ($headers->getAll() as $hdr) { if (null != ($hdr_val = $hdr->getFieldBody())) { if (!empty($hdr_val)) { DAO_MessageHeader::create($message_id, $hdr->getFieldName(), CerberusParser::fixQuotePrintableString($hdr_val)); } } } // Attachments if (is_array($files) && !empty($files)) { $attachment_path = APP_STORAGE_PATH . '/attachments/'; reset($files); foreach ($files['tmp_name'] as $idx => $file) { if (empty($file) || empty($files['name'][$idx]) || !file_exists($file)) { continue; } $fields = array(DAO_Attachment::MESSAGE_ID => $message_id, DAO_Attachment::DISPLAY_NAME => $files['name'][$idx], DAO_Attachment::MIME_TYPE => $files['type'][$idx], DAO_Attachment::FILE_SIZE => filesize($file)); $file_id = DAO_Attachment::create($fields); $attachment_bucket = sprintf("%03d/", mt_rand(1, 100)); $attachment_file = $file_id; if (!file_exists($attachment_path . $attachment_bucket)) { mkdir($attachment_path . $attachment_bucket, 0775, true); } if (!is_writeable($attachment_path . $attachment_bucket)) { echo "Can't write to bucket " . $attachment_path . $attachment_bucket . "<BR>"; } copy($file, $attachment_path . $attachment_bucket . $attachment_file); @unlink($file); DAO_Attachment::update($file_id, array(DAO_Attachment::FILEPATH => $attachment_bucket . $attachment_file)); } } // add note to message if email failed if ($mail_succeeded === false) { $fields = array(DAO_MessageNote::MESSAGE_ID => $message_id, DAO_MessageNote::CREATED => time(), DAO_MessageNote::WORKER_ID => 0, DAO_MessageNote::CONTENT => 'Exception thrown while sending email: ' . $e->getMessage(), DAO_MessageNote::TYPE => Model_MessageNote::TYPE_ERROR); DAO_MessageNote::create($fields); } } // Post-Reply Change Properties if (isset($properties['closed'])) { switch ($properties['closed']) { case 0: // open $change_fields[DAO_Ticket::IS_WAITING] = 0; $change_fields[DAO_Ticket::IS_CLOSED] = 0; $change_fields[DAO_Ticket::IS_DELETED] = 0; $change_fields[DAO_Ticket::DUE_DATE] = 0; break; case 1: // closed $change_fields[DAO_Ticket::IS_WAITING] = 0; $change_fields[DAO_Ticket::IS_CLOSED] = 1; $change_fields[DAO_Ticket::IS_DELETED] = 0; if (isset($properties['ticket_reopen'])) { @($time = intval(strtotime($properties['ticket_reopen']))); $change_fields[DAO_Ticket::DUE_DATE] = $time; } break; case 2: // waiting $change_fields[DAO_Ticket::IS_WAITING] = 1; $change_fields[DAO_Ticket::IS_CLOSED] = 0; $change_fields[DAO_Ticket::IS_DELETED] = 0; if (isset($properties['ticket_reopen'])) { @($time = intval(strtotime($properties['ticket_reopen']))); $change_fields[DAO_Ticket::DUE_DATE] = $time; } break; } } // Who should handle the followup? if (isset($properties['next_worker_id'])) { $change_fields[DAO_Ticket::NEXT_WORKER_ID] = $properties['next_worker_id']; } // Allow anybody to reply after if (isset($properties['unlock_date']) && !empty($properties['unlock_date'])) { $unlock = strtotime($properties['unlock_date']); if (intval($unlock) > 0) { $change_fields[DAO_Ticket::UNLOCK_DATE] = $unlock; } } // Move if (!empty($properties['bucket_id'])) { // [TODO] Use API to move, or fire event // [TODO] Ensure team/bucket exist list($team_id, $bucket_id) = CerberusApplication::translateTeamCategoryCode($properties['bucket_id']); $change_fields[DAO_Ticket::TEAM_ID] = $team_id; $change_fields[DAO_Ticket::CATEGORY_ID] = $bucket_id; } if (!empty($ticket_id) && !empty($change_fields)) { DAO_Ticket::updateTicket($ticket_id, $change_fields); } // Outbound Reply Event (not automated reply, etc.) if (!empty($worker_id)) { $eventMgr = DevblocksPlatform::getEventService(); $eventMgr->trigger(new Model_DevblocksEvent('ticket.reply.outbound', array('ticket_id' => $ticket_id, 'worker_id' => $worker_id))); } }
function showAddInboxRulePanelAction() { @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'], 'string', '')); @($ticket_id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); $tpl = DevblocksPlatform::getTemplateService(); $tpl_path = $this->_TPL_PATH; $tpl->assign('path', $tpl_path); $tpl->assign('ticket_id', $ticket_id); $tpl->assign('view_id', $view_id); $ticket = DAO_Ticket::getTicket($ticket_id); $tpl->assign('ticket', $ticket); $messages = $ticket->getMessages(); $message = array_shift($messages); /* @var $message CerberusMessage */ $message_headers = $message->getHeaders(); $tpl->assign('message', $message); $tpl->assign('message_headers', $message_headers); // To/Cc $tocc = array(); @($to_list = imap_rfc822_parse_adrlist($message_headers['to'], 'localhost')); @($cc_list = imap_rfc822_parse_adrlist($message_headers['cc'], 'localhost')); if (is_array($to_list)) { foreach ($to_list as $addy) { $tocc[] = $addy->mailbox . '@' . $addy->host; } } if (is_array($cc_list)) { foreach ($cc_list as $addy) { $tocc[] = $addy->mailbox . '@' . $addy->host; } } if (!empty($tocc)) { $tpl->assign('tocc_list', implode(', ', $tocc)); } @($first_address = DAO_Address::get($ticket->first_wrote_address_id)); $tpl->assign('first_address', $first_address); // Grops $groups = DAO_Group::getAll(); $tpl->assign('groups', $groups); // Buckets $team_categories = DAO_Bucket::getTeams(); $tpl->assign('team_categories', $team_categories); // Workers $workers = DAO_Worker::getAll(); $tpl->assign('workers', $workers); $tpl->cache_lifetime = "0"; $tpl->display('file:' . $this->_TPL_PATH . 'tickets/rpc/inbox_rule_panel.tpl'); }
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'); }
function showContactHistoryAction() { $translate = DevblocksPlatform::getTranslationService(); @($ticket_id = DevblocksPlatform::importGPC($_REQUEST['ticket_id'], 'integer')); $tpl = DevblocksPlatform::getTemplateService(); $tpl->assign('path', $this->_TPL_PATH); $ticket = DAO_Ticket::getTicket($ticket_id); $requesters = $ticket->getRequesters(); $contact = DAO_Address::get($ticket->first_wrote_address_id); $tpl->assign('contact', $contact); $visit = CerberusApplication::getVisit(); /* @var $visit CerberusVisit */ $view = C4_AbstractViewLoader::getView('', 'contact_history'); if (null == $view) { $view = new C4_TicketView(); $view->id = 'contact_history'; $view->name = $translate->_('addy_book.history.view.title'); $view->view_columns = array(SearchFields_Ticket::TICKET_LAST_ACTION_CODE, SearchFields_Ticket::TICKET_CREATED_DATE, SearchFields_Ticket::TICKET_TEAM_ID, SearchFields_Ticket::TICKET_CATEGORY_ID); $view->params = array(); $view->renderLimit = 10; $view->renderSortBy = SearchFields_Ticket::TICKET_CREATED_DATE; $view->renderSortAsc = false; } $view->name = vsprintf($translate->_('addy_book.history.view.requester'), intval(count($requesters))); $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, DevblocksSearchCriteria::OPER_EQ, 0)); $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'); }
private function newTicketComment($event) { DevblocksPlatform::getExtensions('cerberusweb.ticket.tab', true); // ticket_comment.id @($comment_id = $event->params['comment_id']); // ticket.id @($ticket_id = $event->params['ticket_id']); // address.id @($address_id = $event->params['address_id']); // text of actual comment. @($comment_text = $event->params['comment']); if (empty($ticket_id) || empty($address_id) || empty($comment_text)) { return; } $setting_manifest = DevblocksPlatform::getExtension(AnswernetLastActionAndAuditLogConfigTab::ID); $setting = $setting_manifest->createInstance(); /* @var $job CerberusCronPageExtension */ $al_comment_enabled = intval($setting->getParam(AnswernetLastActionAndAuditLogConfigTab::AL_COMMENT_ENABLED, 0)); $uf_comment_enabled = intval($setting->getParam(AnswernetLastActionAndAuditLogConfigTab::UF_COMMENT_ENABLED, 0)); if (class_exists('DAO_TicketAuditLog', true)) { if ($al_comment_enabled) { @($address = DAO_Address::get($address_id)); @($worker_id = DAO_Worker::lookupAgentEmail($address->email)); $fields = array(DAO_TicketAuditLog::TICKET_ID => $ticket_id, DAO_TicketAuditLog::WORKER_ID => $worker_id, DAO_TicketAuditLog::CHANGE_DATE => time(), DAO_TicketAuditLog::CHANGE_FIELD => "answernet.last_action_and_audit_log.type.comment", DAO_TicketAuditLog::CHANGE_VALUE => substr($comment_text, 0, 128)); $log_id = DAO_TicketAuditLog::create($fields); unset($fields); } } if ($uf_comment_enabled) { $change_fields[DAO_Ticket::UPDATED_DATE] = time(); DAO_Ticket::updateTicket($ticket_id, $change_fields); unset($change_fields); } }
public function getAddress() { return DAO_Address::get($this->address_id); }
private function _handleTicketClosed($event) { @($ticket_ids = $event->params['ticket_ids']); @($changed_fields = $event->params['changed_fields']); // for anything other than setting is_closed = 1, we don't need to do anything // also don't send if the ticket is being deleted if (!isset($changed_fields[DAO_Ticket::IS_CLOSED]) || 1 != $changed_fields[DAO_Ticket::IS_CLOSED] || isset($changed_fields[DAO_Ticket::IS_DELETED]) && 1 == $changed_fields[DAO_Ticket::IS_DELETED]) { return; } $group_settings = DAO_GroupSettings::getSettings(); if (!empty($ticket_ids)) { $tickets = DAO_Ticket::getTickets($ticket_ids); foreach ($tickets as $ticket) { /* @var $ticket CerberusTicket */ if (!isset($group_settings[$ticket->team_id][DAO_GroupSettings::SETTING_CLOSE_REPLY_ENABLED])) { continue; } if (1 == $ticket->is_deleted) { continue; } if ($group_settings[$ticket->team_id][DAO_GroupSettings::SETTING_CLOSE_REPLY_ENABLED] && !empty($group_settings[$ticket->team_id][DAO_GroupSettings::SETTING_CLOSE_REPLY])) { if (null != ($msg_first = DAO_Ticket::getMessage($ticket->first_message_id))) { // First sender $ticket_sender = ''; $ticket_sender_first = ''; if (null != ($sender_first = DAO_Address::get($msg_first->address_id))) { $ticket_sender = $sender_first->email; $ticket_sender_first = $sender_first->first_name; } // First body $ticket_body = $msg_first->getContent(); } CerberusMail::sendTicketMessage(array('ticket_id' => $ticket->id, 'message_id' => $ticket->first_message_id, 'content' => str_replace(array('#ticket_id#', '#mask#', '#subject#', '#timestamp#', '#sender#', '#sender_first#', '#orig_body#'), array($ticket->id, $ticket->mask, $ticket->subject, date('r'), $ticket_sender, $ticket_sender_first, ltrim($ticket_body)), $group_settings[$ticket->team_id][DAO_GroupSettings::SETTING_CLOSE_REPLY]), 'is_autoreply' => false, 'dont_keep_copy' => true)); } } } }
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::get($ticket_id); // (Action) Forward Email To: // Sanitize and combine all the destination addresses $context_workers = CerberusContexts::getWorkers(CerberusContexts::CONTEXT_TICKET, $ticket->id); if (!is_array($context_workers)) { return; } foreach ($context_workers as $next_worker) { $notify_emails = $next_worker->email; if (empty($notify_emails)) { continue; } } // [TODO] This could be more efficient $messages = DAO_Message::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 = DevblocksPlatform::getPluginSettingsService(); $reply_to = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_FROM, CerberusSettingsDefaults::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); } } }
function render() { $tpl = DevblocksPlatform::getTemplateService(); $translate = DevblocksPlatform::getTranslationService(); $response = DevblocksPlatform::getHttpResponse(); $path = $response->path; array_shift($path); // iphone array_shift($path); // tickets $action = array_shift($path); // current action switch ($action) { case 'display': $feedback_id = array_shift($path); $feedbackEntry = DAO_FeedbackEntry::get($feedback_id); if (!empty($feedbackEntry->quote_address_id)) { if (null != ($address = DAO_Address::get($feedbackEntry->quote_address_id))) { $tpl->assign('address', $address); } } $tpl->assign('feedbackEntry', $feedbackEntry); $tpl->display('file:' . $this->_TPL_PATH . 'feedback/display.tpl'); break; default: $defaults = new C4_AbstractViewModel(); $defaults->class_name = 'View_FeedbackEntry_iPhone'; $defaults->id = self::VIEW_FEEDBACK; $defaults->name = $translate->_('feedback.activity.tab'); $defaults->view_columns = array(SearchFields_FeedbackEntry::LOG_DATE, SearchFields_FeedbackEntry::ADDRESS_EMAIL, SearchFields_FeedbackEntry::SOURCE_URL, SearchFields_FeedbackEntry::QUOTE_MOOD); $defaults->renderSortBy = SearchFields_FeedbackEntry::LOG_DATE; $defaults->renderSortAsc = 0; $view = C4_AbstractViewLoader::getView(self::VIEW_FEEDBACK, $defaults); $tpl->assign('view', $view); $tpl->display('file:' . $this->_TPL_PATH . 'feedback/home.tpl'); break; } }