function getWorkerAddressesAction() { @($worker_id = DevblocksPlatform::importGPC($_REQUEST['worker_id'], 'integer', 0)); $tpl = DevblocksPlatform::getTemplateService(); $tpl->assign('path', $this->_TPL_PATH); $addresses = DAO_AddressToWorker::getByWorker($worker_id); $tpl->assign('addresses', $addresses); $tpl->display('file:' . $this->_TPL_PATH . 'preferences/worker_addresses.tpl'); }
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'))); }
/** * Enter description here... * * @param CerberusParserMessage $message * @return integer */ public static function parseMessage(CerberusParserMessage $message, $options = array()) { /* * options: * 'no_autoreply' */ $logger = DevblocksPlatform::getConsoleLog(); $settings = DevblocksPlatform::getPluginSettingsService(); $helpdesk_senders = CerberusApplication::getHelpdeskSenders(); // Pre-parse mail filters $pre_filters = Model_PreParseRule::getMatches($message); if (is_array($pre_filters) && !empty($pre_filters)) { // Load filter action manifests for reuse $ext_action_mfts = DevblocksPlatform::getExtensions('cerberusweb.mail_filter.action', false); // Loop through all matching filters foreach ($pre_filters as $pre_filter) { // Do something with matching filter's actions foreach ($pre_filter->actions as $action_key => $action) { switch ($action_key) { case 'blackhole': return NULL; break; case 'redirect': @($to = $action['to']); CerberusMail::reflect($message, $to); return NULL; break; case 'bounce': @($msg = $action['message']); @($subject = 'Delivery failed: ' . self::fixQuotePrintableString($message->headers['subject'])); // [TODO] Follow the RFC spec on a true bounce if (null != ($fromAddressInst = CerberusParser::getAddressFromHeaders($message->headers))) { CerberusMail::quickSend($fromAddressInst->email, $subject, $msg); } return NULL; break; default: // Plugin pre-parser filter actions if (isset($ext_action_mfts[$action_key])) { if (null != @($ext_action = $ext_action_mfts[$action_key]->createInstance())) { try { /* @var $ext_action Extension_MailFilterAction */ $ext_action->run($pre_filter, $message); } catch (Exception $e) { } } } break; } } } } $headers =& $message->headers; // From if (null == ($fromAddressInst = CerberusParser::getAddressFromHeaders($headers))) { $logger->err("[Parser] 'From' address could not be created."); return NULL; } // To/Cc/Bcc $to = array(); $sTo = @$headers['to']; $bIsNew = true; if (!empty($sTo)) { // [TODO] Do we still need this RFC address parser? $to = CerberusParser::parseRfcAddress($sTo); } // Subject // Fix quote printable subject (quoted blocks can appear anywhere in subject) $sSubject = ""; if (isset($headers['subject']) && !empty($headers['subject'])) { $sSubject = $headers['subject']; if (is_array($sSubject)) { $sSubject = array_shift($sSubject); } } // The subject can still end up empty after QP decode if (empty($sSubject)) { $sSubject = "(no subject)"; } // Date $iDate = @strtotime($headers['date']); // If blank, or in the future, set to the current date if (empty($iDate) || $iDate > time()) { $iDate = time(); } // Is banned? if (1 == $fromAddressInst->is_banned) { $logger->info("[Parser] Ignoring ticket from banned address: " . $fromAddressInst->email); return NULL; } // Overloadable $enumSpamTraining = ''; // Message Id / References / In-Reply-To @($sMessageId = $headers['message-id']); $body_append_text = array(); $body_append_html = array(); // [mdf]Check attached files before creating the ticket because we may need to overwrite the message-id // also store any contents of rfc822 files so we can include them after the body foreach ($message->files as $filename => $file) { /* @var $file ParserFile */ switch ($file->mime_type) { case 'message/rfc822': $full_filename = $file->tmpname; $mail = mailparse_msg_parse_file($full_filename); $struct = mailparse_msg_get_structure($mail); $msginfo = mailparse_msg_get_part_data($mail); $inline_headers = $msginfo['headers']; if (isset($headers['from']) && (strtolower(substr($headers['from'], 0, 11)) == 'postmaster@' || strtolower(substr($headers['from'], 0, 14)) == 'mailer-daemon@')) { $headers['in-reply-to'] = $inline_headers['message-id']; } break; } } // [JAS] [TODO] References header may contain multiple message-ids to find if (null != ($ids = self::findParentMessage($headers))) { $bIsNew = false; $id = $ids['ticket_id']; $msgid = $ids['message_id']; // Is it a worker reply from an external client? If so, proxy if (null != ($worker_address = DAO_AddressToWorker::getByAddress($fromAddressInst->email))) { $logger->info("[Parser] Handling an external worker response from " . $fromAddressInst->email); if (!DAO_Ticket::isTicketRequester($worker_address->address, $id)) { // Watcher Commands [TODO] Document on wiki/etc if (0 != ($matches = preg_match_all("/\\[(.*?)\\]/i", $message->headers['subject'], $commands))) { @($command = strtolower(array_pop($commands[1]))); $logger->info("[Parser] Worker command: " . $command); switch ($command) { case 'close': DAO_Ticket::updateTicket($id, array(DAO_Ticket::IS_CLOSED => CerberusTicketStatus::CLOSED)); break; case 'take': DAO_Ticket::updateTicket($id, array(DAO_Ticket::NEXT_WORKER_ID => $worker_address->worker_id)); break; case 'comment': $comment_id = DAO_TicketComment::create(array(DAO_TicketComment::ADDRESS_ID => $fromAddressInst->id, DAO_TicketComment::CREATED => time(), DAO_TicketComment::TICKET_ID => $id, DAO_TicketComment::COMMENT => $message->body)); return $id; break; default: // Typo? break; } } $attachment_files = array(); $attachment_files['name'] = array(); $attachment_files['type'] = array(); $attachment_files['tmp_name'] = array(); $attachment_files['size'] = array(); $i = 0; foreach ($message->files as $filename => $file) { $attachment_files['name'][$i] = $filename; $attachment_files['type'][$i] = $file->mime_type; $attachment_files['tmp_name'][$i] = $file->tmpname; $attachment_files['size'][$i] = $file->file_size; $i++; } CerberusMail::sendTicketMessage(array('message_id' => $msgid, 'content' => $message->body, 'files' => $attachment_files, 'agent_id' => $worker_address->worker_id)); return $id; } else { // ... worker is a requester, treat as normal $logger->info("[Parser] The external worker was a ticket requester, so we're not treating them as a watcher."); } } else { // Reply: Not sent by a worker /* * [TODO] check that this sender is a requester on the matched ticket * Otherwise blank out the $id */ } } $group_id = 0; if (empty($id)) { // New Ticket $sMask = CerberusApplication::generateTicketMask(); $groups = DAO_Group::getAll(); // Routing new tickets if (null != ($routing_rules = Model_MailToGroupRule::getMatches($fromAddressInst, $message))) { if (is_array($routing_rules)) { foreach ($routing_rules as $rule) { // Only end up with the last 'move' action (ignore the previous) if (isset($rule->actions['move'])) { $group_id = intval($rule->actions['move']['group_id']); // We don't need to move again when running rule actions unset($rule->actions['move']); } } } } // Make sure the group exists if (!isset($groups[$group_id])) { $group_id = null; } // Last ditch effort to check for a default group to deliver to if (empty($group_id)) { if (null != ($default_team = DAO_Group::getDefaultGroup())) { $group_id = $default_team->id; } else { // Bounce return null; } } // [JAS] It's important to not set the group_id on the ticket until the messages exist // or inbox filters will just abort. $fields = array(DAO_Ticket::MASK => $sMask, DAO_Ticket::SUBJECT => $sSubject, DAO_Ticket::IS_CLOSED => 0, DAO_Ticket::FIRST_WROTE_ID => intval($fromAddressInst->id), DAO_Ticket::LAST_WROTE_ID => intval($fromAddressInst->id), DAO_Ticket::CREATED_DATE => $iDate, DAO_Ticket::UPDATED_DATE => $iDate, DAO_Ticket::LAST_ACTION_CODE => CerberusTicketActionCode::TICKET_OPENED); $id = DAO_Ticket::createTicket($fields); // Apply routing actions to our new ticket ID if (isset($routing_rules) && is_array($routing_rules)) { foreach ($routing_rules as $rule) { $rule->run($id); } } } // [JAS]: Add requesters to the ticket if (!empty($fromAddressInst->id) && !empty($id)) { // Don't add a requester if the sender is a helpdesk address if (isset($helpdesk_senders[$fromAddressInst->email])) { $logger->info("[Parser] Not adding ourselves as a requester: " . $fromAddressInst->email); } else { DAO_Ticket::createRequester($fromAddressInst->id, $id); } } // Add the other TO/CC addresses to the ticket // [TODO] This should be cleaned up and optimized if ($settings->get('cerberusweb.core', CerberusSettings::PARSER_AUTO_REQ, 0)) { @($autoreq_exclude_list = $settings->get('cerberusweb.core', CerberusSettings::PARSER_AUTO_REQ_EXCLUDE, '')); $destinations = self::getDestinations($headers); if (is_array($destinations) && !empty($destinations)) { // Filter out any excluded requesters if (!empty($autoreq_exclude_list)) { @($autoreq_exclude = DevblocksPlatform::parseCrlfString($autoreq_exclude_list)); if (is_array($autoreq_exclude) && !empty($autoreq_exclude)) { foreach ($autoreq_exclude as $excl_pattern) { $excl_regexp = DevblocksPlatform::parseStringAsRegExp($excl_pattern); // Check all destinations for this pattern foreach ($destinations as $idx => $dest) { if (@preg_match($excl_regexp, $dest)) { unset($destinations[$idx]); } } } } } foreach ($destinations as $dest) { if (null != ($destInst = CerberusApplication::hashLookupAddress($dest, true))) { // Skip if the destination is one of our senders or the matching TO if (isset($helpdesk_senders[$destInst->email])) { continue; } DAO_Ticket::createRequester($destInst->id, $id); } } } } $attachment_path = APP_STORAGE_PATH . '/attachments/'; // [TODO] This should allow external attachments (S3) $fields = array(DAO_Message::TICKET_ID => $id, DAO_Message::CREATED_DATE => $iDate, DAO_Message::ADDRESS_ID => $fromAddressInst->id); $email_id = DAO_Message::create($fields); // Content DAO_MessageContent::create($email_id, $message->body); // Headers foreach ($headers as $hk => $hv) { DAO_MessageHeader::create($email_id, $hk, $hv); } // [mdf] Loop through files to insert attachment records in the db, and move temporary files if (!empty($email_id)) { foreach ($message->files as $filename => $file) { /* @var $file ParserFile */ //[mdf] skip rfc822 messages since we extracted their content above if ($file->mime_type == 'message/rfc822') { continue; } $fields = array(DAO_Attachment::MESSAGE_ID => $email_id, DAO_Attachment::DISPLAY_NAME => $filename, DAO_Attachment::MIME_TYPE => $file->mime_type, DAO_Attachment::FILE_SIZE => intval($file->file_size)); $file_id = DAO_Attachment::create($fields); if (empty($file_id)) { @unlink($file->tmpname); // remove our temp file continue; } // Make file attachments use buckets so we have a max per directory $attachment_bucket = sprintf("%03d/", mt_rand(1, 100)); $attachment_file = $file_id; if (!file_exists($attachment_path . $attachment_bucket)) { @mkdir($attachment_path . $attachment_bucket, 0770, true); // [TODO] Needs error checking } rename($file->getTempFile(), $attachment_path . $attachment_bucket . $attachment_file); // [TODO] Split off attachments into its own DAO DAO_Attachment::update($file_id, array(DAO_Attachment::FILEPATH => $attachment_bucket . $attachment_file)); } } // Pre-load custom fields if (isset($message->custom_fields) && !empty($message->custom_fields)) { foreach ($message->custom_fields as $cf_id => $cf_val) { if (is_array($cf_val) && !empty($cf_val) || !is_array($cf_val) && 0 != strlen($cf_val)) { DAO_CustomFieldValue::setFieldValue('cerberusweb.fields.source.ticket', $id, $cf_id, $cf_val); } } } // Finalize our new ticket details (post-message creation) if ($bIsNew && !empty($id) && !empty($email_id)) { // First thread (needed for anti-spam) DAO_Ticket::updateTicket($id, array(DAO_Ticket::FIRST_MESSAGE_ID => $email_id)); // Prime the change fields (which a few things like anti-spam might change before we commit) $change_fields = array(DAO_Ticket::TEAM_ID => $group_id); $out = CerberusBayes::calculateTicketSpamProbability($id); if (!empty($group_id)) { @($spam_threshold = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_SPAM_THRESHOLD, 80)); @($spam_action = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_SPAM_ACTION, '')); @($spam_action_param = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_SPAM_ACTION_PARAM, '')); if ($out['probability'] * 100 >= $spam_threshold) { $enumSpamTraining = CerberusTicketSpamTraining::SPAM; switch ($spam_action) { default: case 0: // do nothing break; case 1: // delete $change_fields[DAO_Ticket::IS_CLOSED] = 1; $change_fields[DAO_Ticket::IS_DELETED] = 1; break; case 2: // move $buckets = DAO_Bucket::getAll(); // Verify bucket exists if (!empty($spam_action_param) && isset($buckets[$spam_action_param])) { $change_fields[DAO_Ticket::TEAM_ID] = $group_id; $change_fields[DAO_Ticket::CATEGORY_ID] = $spam_action_param; } break; } } } // end spam training // Save properties if (!empty($change_fields)) { DAO_Ticket::updateTicket($id, $change_fields); } } // Reply notifications (new messages are handled by 'move' listener) if (!$bIsNew) { // Inbound Reply Event $eventMgr = DevblocksPlatform::getEventService(); $eventMgr->trigger(new Model_DevblocksEvent('ticket.reply.inbound', array('ticket_id' => $id))); } // New ticket processing if ($bIsNew) { // Auto reply @($autoreply_enabled = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_AUTO_REPLY_ENABLED, 0)); @($autoreply = DAO_GroupSettings::get($group_id, DAO_GroupSettings::SETTING_AUTO_REPLY, '')); /* * Send the group's autoreply if one exists, as long as this ticket isn't spam */ if (!isset($options['no_autoreply']) && $autoreply_enabled && !empty($autoreply) && $enumSpamTraining != CerberusTicketSpamTraining::SPAM) { CerberusMail::sendTicketMessage(array('ticket_id' => $id, 'message_id' => $email_id, 'content' => str_replace(array('#ticket_id#', '#mask#', '#subject#', '#timestamp#', '#sender#', '#sender_first#', '#orig_body#'), array($id, $sMask, $sSubject, date('r'), $fromAddressInst->email, $fromAddressInst->first_name, ltrim($message->body)), $autoreply), 'is_autoreply' => true, 'dont_keep_copy' => true)); } } // end bIsNew unset($message); // Re-open and update our date on new replies if (!$bIsNew) { DAO_Ticket::updateTicket($id, array(DAO_Ticket::UPDATED_DATE => time(), DAO_Ticket::IS_WAITING => 0, DAO_Ticket::IS_CLOSED => 0, DAO_Ticket::IS_DELETED => 0, DAO_Ticket::LAST_WROTE_ID => $fromAddressInst->id, DAO_Ticket::LAST_ACTION_CODE => CerberusTicketActionCode::TICKET_CUSTOMER_REPLY)); // [TODO] The TICKET_CUSTOMER_REPLY should be sure of this message address not being a worker } @imap_errors(); // Prevent errors from spilling out into STDOUT return $id; }
private function _handleImportWorker($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; $isSuperuser = (int) $xml->is_superuser; // Dupe check worker email if (null != ($worker_id = DAO_Worker::lookupAgentEmail($sEmail))) { $logger->info('[Importer] Avoiding creating duplicate worker #' . $worker_id . ' (' . $sEmail . ')'); return true; } $worker_id = DAO_Worker::create($sEmail, CerberusApplication::generatePassword(8), $sFirstName, $sLastName, ''); DAO_Worker::updateAgent($worker_id, array(DAO_Worker::PASSWORD => $sPassword, DAO_Worker::IS_SUPERUSER => intval($isSuperuser))); // Address to Worker DAO_AddressToWorker::assign($sEmail, $worker_id); DAO_AddressToWorker::update($sEmail, array(DAO_AddressToWorker::IS_CONFIRMED => 1)); $logger->info('[Importer] Imported worker #' . $worker_id . ' (' . $sEmail . ')'); DAO_Worker::clearCache(); return true; }
// 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); } } // Send a first ticket which allows people to reply for support if (null !== ($default_from = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM, ''))) { $message = new CerberusParserMessage(); $message->headers['from'] = '"WebGroup Media, LLC." <*****@*****.**>';
function showTab() { $tpl = DevblocksPlatform::getTemplateService(); $tpl->assign('path', $this->tpl_path); $tpl->cache_lifetime = "0"; $worker = CerberusApplication::getActiveWorker(); $tpl->assign('worker', $worker); $groups = DAO_Group::getAll(); $tpl->assign('groups', $groups); $group_buckets = DAO_Bucket::getTeams(); $tpl->assign('group_buckets', $group_buckets); $memberships = $worker->getMemberships(); $tpl->assign('memberships', $memberships); $addresses = DAO_AddressToWorker::getByWorker($worker->id); $tpl->assign('addresses', $addresses); @($notifications = DAO_WorkerMailForward::getWhere(sprintf("%s = %d", DAO_WorkerMailForward::WORKER_ID, $worker->id))); $tpl->assign('notifications', $notifications); $assign_notify_email = DAO_WorkerPref::get($worker->id, ChWatchersPlugin::WORKER_PREF_ASSIGN_EMAIL, ''); $tpl->assign('assign_notify_email', $assign_notify_email); $tpl->display('file:' . $this->tpl_path . '/preferences/watchers.tpl'); }
private function _sendConfirmationEmail($to, $worker) { $translate = DevblocksPlatform::getTranslationService(); $settings = DevblocksPlatform::getPluginSettingsService(); $url_writer = DevblocksPlatform::getUrlService(); $tpl = DevblocksPlatform::getTemplateService(); // Tentatively assign the e-mail address to this worker DAO_AddressToWorker::assign($to, $worker->id); // Create a confirmation code and save it $code = CerberusApplication::generatePassword(20); DAO_AddressToWorker::update($to, array(DAO_AddressToWorker::CODE => $code, DAO_AddressToWorker::CODE_EXPIRE => time() + 24 * 60 * 60)); // Email the confirmation code to the address // [TODO] This function can return false, and we need to do something different if it does. CerberusMail::quickSend($to, vsprintf($translate->_('prefs.address.confirm.mail.subject'), $settings->get('cerberusweb.core', CerberusSettings::HELPDESK_TITLE)), vsprintf($translate->_('prefs.address.confirm.mail.body'), array($worker->getName(), $url_writer->write('c=preferences&a=confirm_email&code=' . $code, true)))); $output = array(vsprintf($translate->_('prefs.address.confirm.mail.subject'), $to)); $tpl->assign('pref_success', $output); }
private function _newTicketComment($event) { @($comment_id = $event->params['comment_id']); @($ticket_id = $event->params['ticket_id']); @($address_id = $event->params['address_id']); @($comment = $event->params['comment']); if (empty($ticket_id) || empty($address_id) || empty($comment)) { return; } // Resolve the address ID if (null == ($address = DAO_Address::get($address_id))) { return; } // Try to associate the author with a worker if (null == ($worker_addy = DAO_AddressToWorker::getByAddress($address->email))) { return; } if (null == ($worker = DAO_Worker::getAgent($worker_addy->worker_id))) { return; } $url_writer = DevblocksPlatform::getUrlService(); $mail_service = DevblocksPlatform::getMailService(); $mailer = null; // lazy load $settings = CerberusSettings::getInstance(); $default_from = $settings->get(CerberusSettings::DEFAULT_REPLY_FROM, ''); $default_personal = $settings->get(CerberusSettings::DEFAULT_REPLY_PERSONAL, ''); if (null == ($ticket = DAO_Ticket::getTicket($ticket_id))) { return; } // (Action) Forward E-mail: // Sanitize and combine all the destination addresses $next_worker = DAO_Worker::getAgent($ticket->next_worker_id); $notify_emails = $next_worker->email; if (empty($notify_emails)) { return; } if (null == @($last_message = end($ticket->getMessages()))) { /* @var $last_message CerberusMessage */ continue; } if (null == @($last_headers = $last_message->getHeaders())) { continue; } $reply_to = $default_from; $reply_personal = $default_personal; // 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; } @($group_personal = DAO_GroupSettings::get($ticket->team_id, DAO_GroupSettings::SETTING_REPLY_PERSONAL)); if (!empty($group_personal)) { $reply_personal = $group_personal; } } try { if (null == $mailer) { $mailer = $mail_service->getMailer(CerberusMail::getMailerDefaults()); } // Create the message $mail = $mail_service->createMessage(); $mail->setTo(array($notify_emails)); $mail->setFrom(array($reply_to => $reply_personal)); $mail->setReplyTo($reply_to); $mail->setSubject(sprintf("[RW: comment #%s]: %s [comment]", $ticket->mask, $ticket->subject)); $headers = $mail->getHeaders(); if (false !== @($in_reply_to = $last_headers['in-reply-to'])) { $headers->addTextHeader('References', $in_reply_to); $headers->addTextHeader('In-Reply-To', $in_reply_to); } // Build the body $comment_text = sprintf("%s (%s) comments:\r\n%s\r\n", $worker->getName(), $address->email, $comment); $headers->addTextHeader('X-Mailer', 'Cerberus Helpdesk (Build ' . APP_BUILD . ')'); $headers->addTextHeader('Precedence', 'List'); $headers->addTextHeader('Auto-Submitted', 'auto-generated'); $mail->setBody($comment_text); $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 showWatcherPanelAction() { @($id = DevblocksPlatform::importGPC($_REQUEST['id'], 'integer', 0)); $tpl = DevblocksPlatform::getTemplateService(); $tpl->cache_lifetime = "0"; $tpl->assign('path', $this->_TPL_PATH); $active_worker = CerberusApplication::getActiveWorker(); if (null != ($filter = DAO_WatcherMailFilter::get($id))) { $tpl->assign('filter', $filter); } $groups = DAO_Group::getAll(); $tpl->assign('groups', $groups); $buckets = DAO_Bucket::getAll(); $tpl->assign('buckets', $buckets); $group_buckets = DAO_Bucket::getTeams(); $tpl->assign('group_buckets', $group_buckets); $memberships = $active_worker->getMemberships(); $tpl->assign('memberships', $memberships); $addresses = DAO_AddressToWorker::getByWorker($active_worker->id); $tpl->assign('addresses', $addresses); $workers = DAO_Worker::getAllActive(); $tpl->assign('workers', $workers); // Custom Fields: Ticket $ticket_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Ticket::ID); $tpl->assign('ticket_fields', $ticket_fields); // Custom Fields: Address $address_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Address::ID); $tpl->assign('address_fields', $address_fields); // Custom Fields: Orgs $org_fields = DAO_CustomField::getBySource(ChCustomFieldSource_Org::ID); $tpl->assign('org_fields', $org_fields); $tpl->display('file:' . $this->_TPL_PATH . 'preferences/peek.tpl'); }