/** * @param Model_DevblocksEvent $event */ function handleEvent(Model_DevblocksEvent $event) { switch ($event->id) { case 'cron.maint': $records_removed = 0; $logger = DevblocksPlatform::getConsoleLog(); $logger->info("[Answernet.com Maint] Starting Purging Contact Addresses task"); @set_time_limit(0); // Unlimited (if possible) @ini_set('memory_limit', '128M'); $logger->info("[Answernet.com Maint] Overloaded memory_limit to: " . ini_get('memory_limit')); $logger->info("[Answernet.com Maint] Overloaded max_execution_time to: " . ini_get('max_execution_time')); $runtime = microtime(true); //Do something $db = DevblocksPlatform::getDatabaseService(); $sql = "SELECT a.id "; $sql .= "FROM address a "; $sql .= "LEFT JOIN message m ON a.id = m.address_id "; $sql .= "LEFT JOIN requester r ON a.id = r.address_id "; $sql .= "LEFT JOIN ticket_comment tc ON a.id = tc.address_id "; $sql .= "WHERE a.contact_org_id = 0 "; $sql .= "AND m.address_id IS NULL "; $sql .= "AND r.address_id IS NULL "; $sql .= "AND tc.address_id IS NULL "; $sql .= "ORDER BY a.id ASC "; $rs = $db->Execute($sql); while (!$rs->EOF) { // Loop though the records. DAO_Address::delete($rs->fields['id']); // Increament the records removed connecter $records_removed++; $rs->MoveNext(); } $logger->info("[Answernet.com Maint] Total Records Removed: " . $records_removed); $logger->info("[Answernet.com Maint] Total Runtime: " . (microtime(true) - $runtime) * 1000 . " ms"); break; } }
function saveAccountAction() { @($first_name = DevblocksPlatform::importGPC($_REQUEST['first_name'], 'string', '')); @($last_name = DevblocksPlatform::importGPC($_REQUEST['last_name'], 'string', '')); @($change_password = DevblocksPlatform::importGPC($_REQUEST['change_password'], 'string', '')); @($change_password2 = DevblocksPlatform::importGPC($_REQUEST['change_password2'], 'string', '')); $tpl = DevblocksPlatform::getTemplateService(); $umsession = UmPortalHelper::getSession(); $active_user = $umsession->getProperty('sc_login', null); if (!empty($active_user)) { $fields = array(DAO_Address::FIRST_NAME => $first_name, DAO_Address::LAST_NAME => $last_name); DAO_Address::update($active_user->id, $fields); $tpl->assign('account_success', true); if (!empty($change_password)) { if (0 == strcmp($change_password, $change_password2)) { DAO_AddressAuth::update($active_user->id, array(DAO_AddressAuth::PASS => md5($change_password))); } else { $tpl->assign('account_error', "The passwords you entered did not match."); } } } DevblocksPlatform::setHttpResponse(new DevblocksHttpResponse(array('portal', UmPortalHelper::getCode(), 'account'))); }
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)); } } } }
/** * pull auth info out of $_POST, check it, return user_id or false * * @return boolean whether login succeeded */ function authenticate() { $umsession = UmPortalHelper::getSession(); @($email = DevblocksPlatform::importGPC($_REQUEST['email'])); @($pass = DevblocksPlatform::importGPC($_REQUEST['pass'])); $valid = false; if (null != ($addy = DAO_Address::lookupAddress($email, false))) { if ($addy->is_registered && !empty($addy->pass) && 0 == strcmp(md5($pass), $addy->pass)) { $valid = true; $umsession->setProperty('sc_login', $addy); } } if ($valid) { return true; } $umsession->setProperty('sc_login', null); return false; }
/** * @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 _handleImportContact($xml) { $settings = CerberusSettings::getInstance(); $logger = DevblocksPlatform::getConsoleLog(); $sFirstName = (string) $xml->first_name; $sLastName = (string) $xml->last_name; $sEmail = (string) $xml->email; $sPassword = (string) $xml->password; $sOrganization = (string) $xml->organization; // Dupe check org if (null != ($address = DAO_Address::lookupAddress($sEmail))) { $logger->info('[Importer] Avoiding creating duplicate contact #' . $address->id . ' (' . $sEmail . ')'); // [TODO] Still associate with org if local blank? // [TODO] Still associate password if local blank? return true; } $fields = array(DAO_Address::FIRST_NAME => $sFirstName, DAO_Address::LAST_NAME => $sLastName, DAO_Address::EMAIL => $sEmail); // Associate SC password if (!empty($sPassword) && $sPassword != md5('')) { $fields[DAO_Address::IS_REGISTERED] = 1; $fields[DAO_Address::PASS] = $sPassword; } $address_id = DAO_Address::create($fields); // Associate with organization if (!empty($sOrganization)) { if (null != ($org_id = DAO_ContactOrg::lookup($sOrganization, true))) { DAO_Address::update($address_id, array(DAO_Address::CONTACT_ORG_ID => $org_id)); } } $logger->info('[Importer] Imported contact #' . $address_id . ' (' . $sEmail . ')'); return true; }
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 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 saveDefaultsAction() { @($timezone = DevblocksPlatform::importGPC($_REQUEST['timezone'], 'string')); @($lang_code = DevblocksPlatform::importGPC($_REQUEST['lang_code'], 'string', 'en_US')); @($default_signature = DevblocksPlatform::importGPC($_REQUEST['default_signature'], 'string')); @($default_signature_pos = DevblocksPlatform::importGPC($_REQUEST['default_signature_pos'], 'integer', 0)); @($reply_box_height = DevblocksPlatform::importGPC($_REQUEST['reply_box_height'], 'integer')); $worker = CerberusApplication::getActiveWorker(); $translate = DevblocksPlatform::getTranslationService(); $tpl = DevblocksPlatform::getTemplateService(); $pref_errors = array(); // Time $_SESSION['timezone'] = $timezone; @date_default_timezone_set($timezone); DAO_WorkerPref::set($worker->id, 'timezone', $timezone); // Language $_SESSION['locale'] = $lang_code; DevblocksPlatform::setLocale($lang_code); DAO_WorkerPref::set($worker->id, 'locale', $lang_code); @($new_password = DevblocksPlatform::importGPC($_REQUEST['change_pass'], 'string')); @($verify_password = DevblocksPlatform::importGPC($_REQUEST['change_pass_verify'], 'string')); //[mdf] if nonempty passwords match, update worker's password if ($new_password != "" && $new_password === $verify_password) { $session = DevblocksPlatform::getSessionService(); $fields = array(DAO_Worker::PASSWORD => md5($new_password)); DAO_Worker::updateAgent($worker->id, $fields); } @($assist_mode = DevblocksPlatform::importGPC($_REQUEST['assist_mode'], 'integer', 0)); DAO_WorkerPref::set($worker->id, 'assist_mode', $assist_mode); @($keyboard_shortcuts = DevblocksPlatform::importGPC($_REQUEST['keyboard_shortcuts'], 'integer', 0)); DAO_WorkerPref::set($worker->id, 'keyboard_shortcuts', $keyboard_shortcuts); @($mail_inline_comments = DevblocksPlatform::importGPC($_REQUEST['mail_inline_comments'], 'integer', 0)); DAO_WorkerPref::set($worker->id, 'mail_inline_comments', $mail_inline_comments); @($mail_always_show_all = DevblocksPlatform::importGPC($_REQUEST['mail_always_show_all'], 'integer', 0)); DAO_WorkerPref::set($worker->id, 'mail_always_show_all', $mail_always_show_all); // Alternate Email Addresses @($new_email = DevblocksPlatform::importGPC($_REQUEST['new_email'], 'string', '')); @($email_delete = DevblocksPlatform::importGPC($_REQUEST['email_delete'], 'array', array())); // Confirm deletions are assigned to the current worker if (!empty($email_delete)) { foreach ($email_delete as $e) { if (null != ($worker_address = DAO_AddressToWorker::getByAddress($e)) && $worker_address->worker_id == $worker->id) { DAO_AddressToWorker::unassign($e); } } } // Assign a new e-mail address if it's legitimate if (!empty($new_email)) { if (null != ($addy = DAO_Address::lookupAddress($new_email, true))) { if (null == ($assigned = DAO_AddressToWorker::getByAddress($new_email))) { $this->_sendConfirmationEmail($new_email, $worker); } else { $pref_errors[] = vsprintf($translate->_('prefs.address.exists'), $new_email); } } else { $pref_errors[] = vsprintf($translate->_('prefs.address.invalid'), $new_email); } } $tpl->assign('pref_errors', $pref_errors); DevblocksPlatform::setHttpResponse(new DevblocksHttpResponse(array('preferences'))); }
function showBatchPanelAction() { @($ids = DevblocksPlatform::importGPC($_REQUEST['ids'])); @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'])); $tpl = DevblocksPlatform::getTemplateService(); $tpl->assign('path', $this->_TPL_PATH); $tpl->assign('view_id', $view_id); $unique_sender_ids = array(); $unique_subjects = array(); if (!empty($ids)) { $ticket_ids = DevblocksPlatform::parseCsvString($ids); if (empty($ticket_ids)) { break; } $tickets = DAO_Ticket::getTickets($ticket_ids); if (is_array($tickets)) { foreach ($tickets as $ticket) { /* @var $ticket CerberusTicket */ $ptr =& $unique_sender_ids[$ticket->first_wrote_address_id]; $ptr = intval($ptr) + 1; $ptr =& $unique_subjects[$ticket->subject]; $ptr = intval($ptr) + 1; } } arsort($unique_subjects); // sort by occurrences $senders = DAO_Address::getWhere(sprintf("%s IN (%s)", DAO_Address::ID, implode(',', array_keys($unique_sender_ids)))); foreach ($senders as $sender) { $ptr =& $unique_senders[$sender->email]; $ptr = intval($ptr) + 1; } arsort($unique_senders); unset($senders); unset($unique_sender_ids); @$tpl->assign('ticket_ids', $ticket_ids); @$tpl->assign('unique_senders', $unique_senders); @$tpl->assign('unique_subjects', $unique_subjects); } // Teams $teams = DAO_Group::getAll(); $tpl->assign('teams', $teams); // Categories $team_categories = DAO_Bucket::getTeams(); // [TODO] Cache these $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); $tpl->display('file:' . $this->_TPL_PATH . 'tickets/rpc/batch_panel.tpl'); }
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 runMacroAction() { @($macro_id = DevblocksPlatform::importGPC($_REQUEST['macro_id'], 'integer')); @($ids = DevblocksPlatform::importGPC($_REQUEST['ids'])); @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'], 'string')); $view = C4_AbstractViewLoader::getView($view_id); $ids = explode(',', $ids); if (null !== ($macro = DAO_Macro::get($macro_id))) { switch ($macro->source_extension_id) { case 'cerberusweb.macros.ticket': $fields = array(); // loop over the actions, saving the $params as $fields foreach ($macro->actions as $action => $params) { switch ($action) { case 'cerberusweb.macros.action.assign': $fields['next_worker_id'] = $params['worker_id']; break; case 'cerberusweb.macros.action.move': $fields['team_id'] = $params['group_id']; $fields['category_id'] = $params['bucket_id']; break; case 'cerberusweb.macros.action.status': $fields['is_waiting'] = $params['is_waiting']; $fields['is_closed'] = $params['is_closed']; $fields['is_deleted'] = $params['is_deleted']; break; default: // $fields[] = $params; break; } } // update the ticket DAO_Ticket::updateTicket($ids, $fields); break; case 'cerberusweb.macros.address': foreach ($macro->actions as $action => $params) { switch ($action) { default: DAO_Address::update($ids, $params); } } break; case 'cerberusweb.macros.opportunity': foreach ($macro->actions as $action => $params) { switch ($action) { default: DAO_CrmOpportunity::update($ids, $params); } } case 'cerberusweb.macros.task': foreach ($macro->actions as $action => $params) { switch ($action) { default: DAO_Task::update($ids, $params); } } case 'cerberusweb.macros.organization': foreach ($macro->actions as $action => $params) { switch ($action) { default: DAO_ContactOrg::update($ids, $params); } } default: break; } } $view = C4_AbstractViewLoader::getView($view_id); $view->render(); }
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 saveEntryAction() { $active_worker = CerberusApplication::getActiveWorker(); // Make sure we're an active worker if (empty($active_worker) || empty($active_worker->id)) { return; } @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); @($do_delete = DevblocksPlatform::importGPC($_REQUEST['do_delete'], 'integer', 0)); @($activity_id = DevblocksPlatform::importGPC($_POST['activity_id'], 'integer', 0)); @($time_actual_mins = DevblocksPlatform::importGPC($_POST['time_actual_mins'], 'integer', 0)); @($notes = DevblocksPlatform::importGPC($_POST['notes'], 'string', '')); @($org_str = DevblocksPlatform::importGPC($_POST['org'], 'string', '')); @($source_extension_id = DevblocksPlatform::importGPC($_POST['source_extension_id'], 'string', '')); @($source_id = DevblocksPlatform::importGPC($_POST['source_id'], 'integer', 0)); // Translate org string into org id, if exists $org_id = 0; if (!empty($org_str)) { $org_id = DAO_ContactOrg::lookup($org_str, true); } // Delete entries if (!empty($id) && !empty($do_delete)) { if (null != ($entry = DAO_TimeTrackingEntry::get($id))) { // Check privs if ($active_worker->hasPriv('timetracking.actions.create') && $active_worker->id == $entry->worker_id || $active_worker->hasPriv('timetracking.actions.update_all')) { DAO_TimeTrackingEntry::delete($id); } } return; } // New or modify $fields = array(DAO_TimeTrackingEntry::ACTIVITY_ID => intval($activity_id), DAO_TimeTrackingEntry::TIME_ACTUAL_MINS => intval($time_actual_mins), DAO_TimeTrackingEntry::NOTES => $notes, DAO_TimeTrackingEntry::DEBIT_ORG_ID => intval($org_id)); // Only on new if (empty($id)) { $fields[DAO_TimeTrackingEntry::LOG_DATE] = time(); $fields[DAO_TimeTrackingEntry::SOURCE_EXTENSION_ID] = $source_extension_id; $fields[DAO_TimeTrackingEntry::SOURCE_ID] = intval($source_id); $fields[DAO_TimeTrackingEntry::WORKER_ID] = intval($active_worker->id); } if (empty($id)) { // create $id = DAO_TimeTrackingEntry::create($fields); // Procedurally create a comment $translate = DevblocksPlatform::getTranslationService(); switch ($source_extension_id) { // If ticket, add a comment about the timeslip to the ticket case 'timetracking.source.ticket': $ticket_id = intval($source_id); if (null != ($worker_address = DAO_Address::lookupAddress($active_worker->email, false))) { if (!empty($activity_id)) { $activity = DAO_TimeTrackingActivity::get($activity_id); } if (!empty($org_id)) { $org = DAO_ContactOrg::get($org_id); } $comment = sprintf("== %s ==\n" . "%s %s\n" . "%s %d\n" . "%s %s (%s)\n" . "%s %s\n" . "%s %s\n", $translate->_('timetracking.ui.timetracking'), $translate->_('timetracking.ui.worker'), $active_worker->getName(), $translate->_('timetracking.ui.comment.time_spent'), $time_actual_mins, $translate->_('timetracking.ui.comment.activity'), !empty($activity) ? $activity->name : '', !empty($activity) && $activity->rate > 0.0 ? $translate->_('timetracking.ui.billable') : $translate->_('timetracking.ui.non_billable'), $translate->_('timetracking.ui.comment.organization'), !empty($org) ? $org->name : $translate->_('timetracking.ui.comment.not_set'), $translate->_('timetracking.ui.comment.notes'), $notes); //timetracking.ui.billable timetracking.ui.non_billable $fields = array(DAO_TicketComment::ADDRESS_ID => intval($worker_address->id), DAO_TicketComment::COMMENT => $comment, DAO_TicketComment::CREATED => time(), DAO_TicketComment::TICKET_ID => intval($ticket_id)); DAO_TicketComment::create($fields); } break; } } else { // modify DAO_TimeTrackingEntry::update($id, $fields); } // Custom field saves @($field_ids = DevblocksPlatform::importGPC($_POST['field_ids'], 'array', array())); DAO_CustomFieldValue::handleFormPost(ChCustomFieldSource_TimeEntry::ID, $id, $field_ids); }
function saveEntryAction() { $active_worker = CerberusApplication::getActiveWorker(); // Make sure we're an active worker if (empty($active_worker) || empty($active_worker->id)) { return; } @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); @($do_delete = DevblocksPlatform::importGPC($_REQUEST['do_delete'], 'integer', 0)); @($email = DevblocksPlatform::importGPC($_POST['email'], 'string', '')); @($mood = DevblocksPlatform::importGPC($_POST['mood'], 'integer', 0)); @($quote = DevblocksPlatform::importGPC($_POST['quote'], 'string', '')); @($url = DevblocksPlatform::importGPC($_POST['url'], 'string', '')); @($source_extension_id = DevblocksPlatform::importGPC($_POST['source_extension_id'], 'string', '')); @($source_id = DevblocksPlatform::importGPC($_POST['source_id'], 'integer', 0)); // Translate email string into addy id, if exists $address_id = 0; if (!empty($email)) { if (null != ($author_address = DAO_Address::lookupAddress($email, true))) { $address_id = $author_address->id; } } // Delete entries if (!empty($id) && !empty($do_delete)) { if (null != ($entry = DAO_FeedbackEntry::get($id))) { // Only superusers and owners can delete entries if ($active_worker->is_superuser || $active_worker->id == $entry->worker_id) { DAO_FeedbackEntry::delete($id); } } return; } // New or modify $fields = array(DAO_FeedbackEntry::QUOTE_MOOD => intval($mood), DAO_FeedbackEntry::QUOTE_TEXT => $quote, DAO_FeedbackEntry::QUOTE_ADDRESS_ID => intval($address_id), DAO_FeedbackEntry::SOURCE_URL => $url); // Only on new if (empty($id)) { $fields[DAO_FeedbackEntry::LOG_DATE] = time(); $fields[DAO_FeedbackEntry::WORKER_ID] = $active_worker->id; } if (empty($id)) { // create $id = DAO_FeedbackEntry::create($fields); // Post-create actions if (!empty($source_extension_id) && !empty($source_id)) { switch ($source_extension_id) { case 'feedback.source.ticket': // Create a ticket comment about the feedback (to prevent dupes) if (null == ($worker_address = DAO_Address::lookupAddress($active_worker->email))) { break; } $comment_text = sprintf("== Capture Feedback ==\n" . "Author: %s\n" . "Mood: %s\n" . "\n" . "%s\n", !empty($author_address) ? $author_address->email : 'Anonymous', empty($mood) ? 'Neutral' : (1 == $mood ? 'Praise' : 'Criticism'), $quote); $fields = array(DAO_TicketComment::ADDRESS_ID => $worker_address->id, DAO_TicketComment::COMMENT => $comment_text, DAO_TicketComment::CREATED => time(), DAO_TicketComment::TICKET_ID => intval($source_id)); DAO_TicketComment::create($fields); break; } } } else { // modify DAO_FeedbackEntry::update($id, $fields); } // Custom field saves @($field_ids = DevblocksPlatform::importGPC($_POST['field_ids'], 'array', array())); DAO_CustomFieldValue::handleFormPost(ChCustomFieldSource_FeedbackEntry::ID, $id, $field_ids); }
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); } }
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); }
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); } }
private static function _markTicketAs($ticket_id, $spam = true) { // [TODO] Make sure we can't retrain tickets which are already spam trained // [TODO] This is a performance killer $ticket = DAO_Ticket::getTicket($ticket_id); if ($ticket->spam_training != CerberusTicketSpamTraining::BLANK) { return TRUE; } // pull up text of first ticket message // [TODO] This is a performance killer $first_message = DAO_Ticket::getMessage($ticket->first_message_id); if (empty($first_message)) { return FALSE; } // [TODO] This is a performance killer $headers = DAO_MessageHeader::getAll($first_message->id); // 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(); if (strlen($content) > self::MAX_BODY_LENGTH) { $content = substr($content, 0, strrpos(substr($content, 0, self::MAX_BODY_LENGTH), ' ')); } $words = self::processText($content); // Train interesting words as spam/notspam // $out = self::_calculateSpamProbability($words); // self::_trainWords($out['words'],$spam); self::_trainWords($words, $spam); // [TODO] Testing, train all words // Increase the bayes_stats spam or notspam total count by 1 // [TODO] This is a performance killer (could be done in batches) if ($spam) { DAO_Bayes::addOneToSpamTotal(); DAO_Address::addOneToSpamTotal($ticket->first_wrote_address_id); } else { DAO_Bayes::addOneToNonSpamTotal(); DAO_Address::addOneToNonSpamTotal($ticket->first_wrote_address_id); } // Forced training should leave a cache of 0.0001 or 0.9999 on the ticket table $fields = array('spam_score' => $spam ? 0.9999 : 0.0001, 'spam_training' => $spam ? CerberusTicketSpamTraining::SPAM : CerberusTicketSpamTraining::NOT_SPAM); DAO_Ticket::updateTicket($ticket_id, $fields); return TRUE; }
/** * 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; }
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'); }
$sales_spam_bid = DAO_Bucket::create('Spam', $sales_gid); DAO_GroupSettings::set($sales_gid, DAO_GroupSettings::SETTING_SPAM_ACTION, '2'); DAO_GroupSettings::set($sales_gid, DAO_GroupSettings::SETTING_SPAM_ACTION_PARAM, $sales_spam_bid); DAO_GroupSettings::set($sales_gid, DAO_GroupSettings::SETTING_SPAM_THRESHOLD, '85'); // Default catchall DAO_Group::updateTeam($dispatch_gid, array(DAO_Group::IS_DEFAULT => 1)); } // If this worker doesn't exist, create them if (null === ($lookup = DAO_Worker::lookupAgentEmail($worker_email))) { $worker_id = DAO_Worker::create($worker_email, $worker_pass, 'Super', 'User', 'Administrator'); // Superuser bit $fields = array(DAO_Worker::IS_SUPERUSER => 1); DAO_Worker::updateAgent($worker_id, $fields); // Add the worker e-mail to the addresses table if (!empty($worker_email)) { DAO_Address::lookupAddress($worker_email, true); } // Authorize this e-mail address (watchers, etc.) DAO_AddressToWorker::assign($worker_email, $worker_id); DAO_AddressToWorker::update($worker_email, array(DAO_AddressToWorker::IS_CONFIRMED => 1)); // Default group memberships if (!empty($dispatch_gid)) { DAO_Group::setTeamMember($dispatch_gid, $worker_id, true); } if (!empty($support_gid)) { DAO_Group::setTeamMember($support_gid, $worker_id, true); } if (!empty($sales_gid)) { DAO_Group::setTeamMember($sales_gid, $worker_id, true); } }
/** * Looks up an e-mail address using a revolving cache. This is helpful * in situations where you may look up the same e-mail address multiple * times (reports, audit log, views) and you don't want to waste code * filtering out dupes. * * @param string $address The e-mail address to look up * @param bool $create Should the address be created if not found? * @return Model_Address The address object or NULL * * @todo [JAS]: Move this to a global cache/hash registry */ public static function hashLookupAddress($email, $create = false) { static $hash_address_to_id = array(); static $hash_hits = array(); static $hash_size = 0; if (isset($hash_address_to_id[$email])) { $return = $hash_address_to_id[$email]; @($hash_hits[$email] = intval($hash_hits[$email]) + 1); $hash_size++; // [JAS]: if our hash grows past our limit, crop hits array + intersect keys if ($hash_size > 250) { arsort($hash_hits); $hash_hits = array_slice($hash_hits, 0, 100, true); $hash_address_to_id = array_intersect_key($hash_address_to_id, $hash_hits); $hash_size = count($hash_address_to_id); } return $return; } $address = DAO_Address::lookupAddress($email, $create); if (!empty($address)) { $hash_address_to_id[$email] = $address; } return $address; }
public function getAddress() { return DAO_Address::get($this->address_id); }
function doRegisterConfirmAction() { @($email = DevblocksPlatform::importGPC($_REQUEST['email'], 'string', '')); @($code = trim(DevblocksPlatform::importGPC($_REQUEST['code'], 'string', ''))); @($pass = DevblocksPlatform::importGPC($_REQUEST['pass'], 'string', '')); $tpl = DevblocksPlatform::getTemplateService(); $tpl->assign('register_email', $email); $tpl->assign('register_code', $code); if (!empty($email) && !empty($pass) && !empty($code)) { if (null != ($addy = DAO_Address::lookupAddress($email, false)) && !$addy->is_registered && !empty($addy->pass) && 0 == strcasecmp($code, $addy->pass)) { $fields = array(DAO_Address::IS_REGISTERED => 1, DAO_Address::PASS => md5($pass)); DAO_Address::update($addy->id, $fields); } else { $tpl->assign('register_error', sprintf("The confirmation code you entered does not match our records. Try again.")); DevblocksPlatform::setHttpResponse(new DevblocksHttpResponse(array('portal', UmPortalHelper::getCode(), 'register', 'confirm'))); return; } } else { $tpl->assign('register_error', sprintf("You must enter a valid e-mail address, confirmation code and desired password to continue.")); DevblocksPlatform::setHttpResponse(new DevblocksHttpResponse(array('portal', UmPortalHelper::getCode(), 'register', 'confirm'))); return; } }
private function _sendConfirmation($email, $link) { $settings = CerberusSettings::getInstance(); $from = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM); $from_personal = $settings->get(CerberusSettings::DEFAULT_REPLY_PERSONAL); $url = DevblocksPlatform::getUrlService(); try { $mail_service = DevblocksPlatform::getMailService(); $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults()); $code = CerberusApplication::generatePassword(8); if (!empty($email) && null != ($addy = DAO_Address::lookupAddress($email, false))) { $fields = array(DAO_AddressAuth::CONFIRM => $code); DAO_AddressAuth::update($addy->id, $fields); } else { return; } $message = $mail_service->createMessage(); $message->setTo($email); $send_from = new Swift_Address($from, $from_personal); $message->setFrom($send_from); $message->setSubject("Account Confirmation Code"); $message->setBody(sprintf("Below is your confirmation code. Please copy and paste it into the confirmation form at:\r\n" . "%s\r\n" . "\r\n" . "Your confirmation code is: %s\r\n" . "\r\n" . "Thanks!\r\n", $link, $code)); $message->headers->set('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')'); $mailer->send($message, $email, $send_from); } catch (Exception $e) { return; } }
function saveWorkerPeekAction() { $translate = DevblocksPlatform::getTranslationService(); $active_worker = CerberusApplication::getActiveWorker(); if (!$active_worker || !$active_worker->is_superuser || DEMO_MODE) { return; } @($id = DevblocksPlatform::importGPC($_POST['id'], 'integer')); @($view_id = DevblocksPlatform::importGPC($_POST['view_id'], 'string')); @($first_name = DevblocksPlatform::importGPC($_POST['first_name'], 'string')); @($last_name = DevblocksPlatform::importGPC($_POST['last_name'], 'string')); @($title = DevblocksPlatform::importGPC($_POST['title'], 'string')); @($email = DevblocksPlatform::importGPC($_POST['email'], 'string')); @($password = DevblocksPlatform::importGPC($_POST['password'], 'string')); @($is_superuser = DevblocksPlatform::importGPC($_POST['is_superuser'], 'integer', 0)); @($disabled = DevblocksPlatform::importGPC($_POST['is_disabled'], 'integer', 0)); @($group_ids = DevblocksPlatform::importGPC($_POST['group_ids'], 'array')); @($group_roles = DevblocksPlatform::importGPC($_POST['group_roles'], 'array')); @($delete = DevblocksPlatform::importGPC($_POST['do_delete'], 'integer', 0)); // [TODO] The superuser set bit here needs to be protected by ACL if (empty($first_name)) { $first_name = "Anonymous"; } if (!empty($id) && !empty($delete)) { // Can't delete or disable self if ($active_worker->id != $id) { DAO_Worker::deleteAgent($id); } } else { if (empty($id) && null == DAO_Worker::lookupAgentEmail($email)) { $workers = DAO_Worker::getAll(); $license = CerberusLicense::getInstance(); if (!empty($license) && !empty($license['serial']) || count($workers) < 3) { // Creating new worker. If password is empty, email it to them if (empty($password)) { $settings = DevblocksPlatform::getPluginSettingsService(); $replyFrom = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_FROM); $replyPersonal = $settings->get('cerberusweb.core', CerberusSettings::DEFAULT_REPLY_PERSONAL, ''); $url = DevblocksPlatform::getUrlService(); $password = CerberusApplication::generatePassword(8); try { $mail_service = DevblocksPlatform::getMailService(); $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults()); $mail = $mail_service->createMessage(); $mail->setTo(array($email => $first_name . ' ' . $last_name)); $mail->setFrom(array($replyFrom => $replyPersonal)); $mail->setSubject('Your new helpdesk login information!'); $mail->generateId(); $headers = $mail->getHeaders(); $headers->addTextHeader('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')'); $body = sprintf("Your new helpdesk login information is below:\r\n" . "\r\n" . "URL: %s\r\n" . "Login: %s\r\n" . "Password: %s\r\n" . "\r\n" . "You should change your password from Preferences after logging in for the first time.\r\n" . "\r\n", $url->write('', true), $email, $password); $mail->setBody($body); if (!$mailer->send($mail)) { throw new Exception('Password notification email failed to send.'); } } catch (Exception $e) { // [TODO] need to report to the admin when the password email doesn't send. The try->catch // will keep it from killing php, but the password will be empty and the user will never get an email. } } $id = DAO_Worker::create($email, $password, '', '', ''); } } // end create worker // Update $fields = array(DAO_Worker::FIRST_NAME => $first_name, DAO_Worker::LAST_NAME => $last_name, DAO_Worker::TITLE => $title, DAO_Worker::EMAIL => $email, DAO_Worker::IS_SUPERUSER => $is_superuser, DAO_Worker::IS_DISABLED => $disabled); // if we're resetting the password if (!empty($password)) { $fields[DAO_Worker::PASSWORD] = md5($password); } // Update worker DAO_Worker::updateAgent($id, $fields); // Update group memberships if (is_array($group_ids) && is_array($group_roles)) { foreach ($group_ids as $idx => $group_id) { if (empty($group_roles[$idx])) { DAO_Group::unsetTeamMember($group_id, $id); } else { DAO_Group::setTeamMember($group_id, $id, 2 == $group_roles[$idx]); } } } // Add the worker e-mail to the addresses table if (!empty($email)) { DAO_Address::lookupAddress($email, true); } // Addresses if (null == DAO_AddressToWorker::getByAddress($email)) { DAO_AddressToWorker::assign($email, $id); DAO_AddressToWorker::update($email, array(DAO_AddressToWorker::IS_CONFIRMED => 1)); } // Custom field saves @($field_ids = DevblocksPlatform::importGPC($_POST['field_ids'], 'array', array())); DAO_CustomFieldValue::handleFormPost(ChCustomFieldSource_Worker::ID, $id, $field_ids); } if (!empty($view_id)) { $view = C4_AbstractViewLoader::getView($view_id); $view->render(); } //DevblocksPlatform::setHttpResponse(new DevblocksHttpResponse(array('config','workers'))); }
function saveContactAction() { $active_worker = CerberusApplication::getActiveWorker(); $db = DevblocksPlatform::getDatabaseService(); @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); @($email = trim(DevblocksPlatform::importGPC($_REQUEST['email'], 'string', ''))); @($first_name = trim(DevblocksPlatform::importGPC($_REQUEST['first_name'], 'string', ''))); @($last_name = trim(DevblocksPlatform::importGPC($_REQUEST['last_name'], 'string', ''))); @($contact_org = trim(DevblocksPlatform::importGPC($_REQUEST['contact_org'], 'string', ''))); @($is_banned = DevblocksPlatform::importGPC($_REQUEST['is_banned'], 'integer', 0)); @($pass = DevblocksPlatform::importGPC($_REQUEST['pass'], 'string', '')); @($unregister = DevblocksPlatform::importGPC($_REQUEST['unregister'], 'integer', 0)); @($view_id = DevblocksPlatform::importGPC($_REQUEST['view_id'], 'string', '')); if ($active_worker->hasPriv('core.addybook.addy.actions.update')) { $contact_org_id = 0; if (!empty($contact_org)) { $contact_org_id = DAO_ContactOrg::lookup($contact_org, true); $contact_org = DAO_ContactOrg::get($contact_org_id); } // Common fields $fields = array(DAO_Address::FIRST_NAME => $first_name, DAO_Address::LAST_NAME => $last_name, DAO_Address::CONTACT_ORG_ID => $contact_org_id, DAO_Address::IS_BANNED => $is_banned); // Are we clearing the contact's login? if ($unregister) { $fields[DAO_Address::IS_REGISTERED] = 0; $fields[DAO_Address::PASS] = ''; } elseif (!empty($pass)) { // Are we changing their password? $fields[DAO_Address::IS_REGISTERED] = 1; $fields[DAO_Address::PASS] = md5($pass); } if ($id == 0) { $fields = $fields + array(DAO_Address::EMAIL => $email); $id = DAO_Address::create($fields); } else { DAO_Address::update($id, $fields); } // Custom field saves @($field_ids = DevblocksPlatform::importGPC($_POST['field_ids'], 'array', array())); DAO_CustomFieldValue::handleFormPost(ChCustomFieldSource_Address::ID, $id, $field_ids); /* * Notify anything that wants to know when Address Peek saves. */ $eventMgr = DevblocksPlatform::getEventService(); $eventMgr->trigger(new Model_DevblocksEvent('address.peek.saved', array('address_id' => $id, 'changed_fields' => $fields))); } if (!empty($view_id)) { $view = C4_AbstractViewLoader::getView($view_id); $view->render(); } }
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); } } }
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); } }