Exemplo n.º 1
0
 /**
  * Insert note to system, send out notification and log.
  *
  * @param int $usr_id The user ID
  * @param int $issue_id The issue ID
  * @param string $title Title of the note
  * @param string $note Note contents
  * @param array $options extra optional options:
  * - (array) cc: extra recipients to notify (usr_id list)
  * - (bool) add_extra_recipients: whether to add recipients in 'cc' to notification list
  * - (bool) closing: If The issue is being closed. Default false
  * - (bool) is_blocked: FIXME
  * - (bool) log: If adding this note should be logged. Default true
  * - (bool) send_notification: Whether to send a notification about this note or not. Default true
  * - (int) parent_id: FIXME
  * - (string) full_message: FIXME
  * - (string) message_id: FIXME
  * - (string) unknown_user: The email address of a user that sent the blocked email that was turned into this note
  * @return int the new note id if the insert worked, -1 or -2 otherwise
  */
 public static function insertNote($usr_id, $issue_id, $title, $note, $options = array())
 {
     if (Validation::isWhitespace($note)) {
         return -2;
     }
     $options = array_merge(array('unknown_user' => null, 'log' => true, 'closing' => false, 'send_notification' => true, 'is_blocked' => false, 'message_id' => null, 'cc' => null, 'full_message' => null, 'parent_id' => null), $options);
     $prj_id = Issue::getProjectID($issue_id);
     // NOTE: workflow may modify the parameters as $data is passed as reference
     $data = array('title' => &$title, 'note' => &$note, 'options' => $options);
     $workflow = Workflow::preNoteInsert($prj_id, $issue_id, $data);
     if ($workflow !== null) {
         // cancel insert of note
         return $workflow;
     }
     // add the poster to the list of people to be subscribed to the notification list
     // only if there is no 'unknown user' and the note is not blocked
     if (!$options['unknown_user'] && !$options['is_blocked']) {
         $note_cc = $options['add_extra_recipients'] ? $options['cc'] : array();
         // always add the current user to the note_cc list
         $note_cc[] = $usr_id;
         $actions = Notification::getDefaultActions($issue_id, User::getEmail($usr_id), 'note');
         foreach ($note_cc as $subscriber_usr_id) {
             Notification::subscribeUser($usr_id, $issue_id, $subscriber_usr_id, $actions);
         }
     }
     $params = array('not_iss_id' => $issue_id, 'not_usr_id' => $usr_id, 'not_created_date' => Date_Helper::getCurrentDateGMT(), 'not_note' => $note, 'not_title' => $title, 'not_message_id' => $options['message_id'] ?: Mail_Helper::generateMessageID());
     if ($options['full_message']) {
         $params['not_full_message'] = $options['full_message'];
     }
     if ($options['is_blocked']) {
         $params['not_is_blocked'] = '1';
     }
     if ($options['parent_id']) {
         $params['not_parent_id'] = $options['parent_id'];
     }
     if ($options['unknown_user']) {
         $params['not_unknown_user'] = $options['unknown_user'];
     }
     $stmt = 'INSERT INTO
                 {{%note}}
              SET ' . DB_Helper::buildSet($params);
     try {
         DB_Helper::getInstance()->query($stmt, $params);
     } catch (DbException $e) {
         return -1;
     }
     $note_id = DB_Helper::get_last_insert_id();
     Issue::markAsUpdated($issue_id, 'note');
     if ($options['log']) {
         // need to save a history entry for this
         History::add($issue_id, $usr_id, 'note_added', 'Note added by {subject}', array('subject' => User::getFullName($usr_id)));
     }
     // send notifications for the issue being updated
     if ($options['send_notification']) {
         $internal_only = true;
         Notification::notify($issue_id, 'notes', $note_id, $internal_only, $options['cc']);
         Workflow::handleNewNote($prj_id, $issue_id, $usr_id, $options['closing'], $note_id);
     }
     // need to return the new note id here so it can
     // be re-used to associate internal-only attachments
     return $note_id;
 }
Exemplo n.º 2
0
 /**
  * TODO: merge use of $options and $email arrays to just $email
  *
  * @param int $issue_id
  * @param string $type type of email
  * @param string $from
  * @param string $to
  * @param string $cc
  * @param string $subject
  * @param string $body
  * @param array $options optional parameters
  * - (int) parent_sup_id
  * - (array) iaf_ids attachment file ids
  * - (bool) add_unknown
  * - (int) ema_id
  * @return int 1 if it worked, -1 otherwise
  */
 public static function sendEmail($issue_id, $type, $from, $to, $cc, $subject, $body, $options = array())
 {
     $parent_sup_id = $options['parent_sup_id'];
     $iaf_ids = $options['iaf_ids'];
     $add_unknown = $options['add_unknown'];
     $ema_id = $options['ema_id'];
     $current_usr_id = Auth::getUserID();
     $prj_id = Issue::getProjectID($issue_id);
     // if we are replying to an existing email, set the In-Reply-To: header accordingly
     $in_reply_to = $parent_sup_id ? self::getMessageIDByID($parent_sup_id) : false;
     // get ID of whoever is sending this.
     $sender_usr_id = User::getUserIDByEmail(Mail_Helper::getEmailAddress($from)) ?: false;
     // remove extra 'Re: ' from subject
     $subject = Mail_Helper::removeExcessRe($subject, true);
     $internal_only = false;
     $message_id = Mail_Helper::generateMessageID();
     // process any files being uploaded
     // from ajax upload, attachment file ids
     if ($iaf_ids) {
         // FIXME: is it correct to use sender from post data?
         $attach_usr_id = $sender_usr_id ?: $current_usr_id;
         Attachment::attachFiles($issue_id, $attach_usr_id, $iaf_ids, false, 'Attachment originated from outgoing email');
     }
     // hack needed to get the full headers of this web-based email
     $full_email = self::buildFullHeaders($issue_id, $message_id, $from, $to, $cc, $subject, $body, $in_reply_to, $iaf_ids);
     // email blocking should only be done if this is an email about an associated issue
     if ($issue_id) {
         $user_info = User::getNameEmail($current_usr_id);
         // check whether the current user is allowed to send this email to customers or not
         if (!self::isAllowedToEmail($issue_id, $user_info['usr_email'])) {
             // add the message body as a note
             $note = Mail_Helper::getCannedBlockedMsgExplanation() . $body;
             $note_options = array('full_message' => $full_email, 'is_blocked' => true);
             Note::insertNote($current_usr_id, $issue_id, $subject, $note, $note_options);
             $email_details = array('from' => $from, 'to' => $to, 'cc' => $cc, 'subject' => $subject, 'body' => &$body, 'message' => &$body, 'title' => $subject);
             Workflow::handleBlockedEmail($prj_id, $issue_id, $email_details, 'web');
             return 1;
         }
     }
     // only send a direct email if the user doesn't want to add the Cc'ed people to the notification list
     if (($add_unknown || Workflow::shouldAutoAddToNotificationList($prj_id)) && $issue_id) {
         // add the recipients to the notification list of the associated issue
         $recipients = array($to);
         $recipients = array_merge($recipients, self::getRecipientsCC($cc));
         foreach ($recipients as $address) {
             if ($address && !Notification::isIssueRoutingSender($issue_id, $address)) {
                 $actions = Notification::getDefaultActions($issue_id, $address, 'add_unknown_user');
                 Notification::subscribeEmail($current_usr_id, $issue_id, Mail_Helper::getEmailAddress($address), $actions);
             }
         }
     } else {
         // Usually when sending out emails associated to an issue, we would
         // simply insert the email in the table and call the Notification::notifyNewEmail() method,
         // but on this case we need to actually send the email to the recipients that are not
         // already in the notification list for the associated issue, if any.
         // In the case of replying to an email that is not yet associated with an issue, then
         // we are always directly sending the email, without using any notification list
         // functionality.
         if ($issue_id) {
             // send direct emails only to the unknown addresses, and leave the rest to be
             // catched by the notification list
             $from = Notification::getFixedFromHeader($issue_id, $from, 'issue');
             // build the list of unknown recipients
             if ($to) {
                 $recipients = array($to);
                 $recipients = array_merge($recipients, self::getRecipientsCC($cc));
             } else {
                 $recipients = self::getRecipientsCC($cc);
             }
             $unknowns = array();
             foreach ($recipients as $address) {
                 if (!Notification::isSubscribedToEmails($issue_id, $address)) {
                     $unknowns[] = $address;
                 }
             }
             if ($unknowns) {
                 $to2 = array_shift($unknowns);
                 $cc2 = implode('; ', $unknowns);
                 // send direct emails
                 self::sendDirectEmail($issue_id, $from, $to2, $cc2, $subject, $body, $_FILES['attachment'], $message_id, $sender_usr_id);
             }
         } else {
             // send direct emails to all recipients, since we don't have an associated issue
             $project_info = Project::getOutgoingSenderAddress(Auth::getCurrentProject());
             // use the project-related outgoing email address, if there is one
             if (!empty($project_info['email'])) {
                 $from = Mail_Helper::getFormattedName(User::getFullName($current_usr_id), $project_info['email']);
             } else {
                 // otherwise, use the real email address for the current user
                 $from = User::getFromHeader($current_usr_id);
             }
             // send direct emails
             self::sendDirectEmail($issue_id, $from, $to, $cc, $subject, $body, $_FILES['attachment'], $message_id);
         }
     }
     $email = array('customer_id' => 'NULL', 'issue_id' => $issue_id, 'ema_id' => $ema_id, 'message_id' => $message_id, 'date' => Date_Helper::getCurrentDateGMT(), 'from' => $from, 'to' => $to, 'cc' => $cc, 'subject' => $subject, 'body' => $body, 'full_email' => $full_email);
     // associate this new email with a customer, if appropriate
     if (Auth::getCurrentRole() == User::getRoleID('Customer')) {
         if ($issue_id) {
             $crm = CRM::getInstance($prj_id);
             try {
                 $contact = $crm->getContact(User::getCustomerContactID($current_usr_id));
                 $issue_contract = $crm->getContract(Issue::getContractID($issue_id));
                 if ($contact->canAccessContract($issue_contract)) {
                     $email['customer_id'] = $issue_contract->getCustomerID();
                 }
             } catch (CRMException $e) {
             }
         } else {
             $customer_id = User::getCustomerID($current_usr_id);
             if ($customer_id && $customer_id != -1) {
                 $email['customer_id'] = $customer_id;
             }
         }
     }
     $email['has_attachment'] = $iaf_ids ? 1 : 0;
     $structure = Mime_Helper::decode($full_email, true, false);
     $email['headers'] = $structure->headers;
     self::insertEmail($email, $structure, $sup_id);
     if ($issue_id) {
         // need to send a notification
         Notification::notifyNewEmail($current_usr_id, $issue_id, $email, $internal_only, false, $type, $sup_id);
         // mark this issue as updated
         $has_customer = $email['customer_id'] && $email['customer_id'] != 'NULL';
         if ($has_customer && (!$current_usr_id || User::getRoleByUser($current_usr_id, $prj_id) == User::getRoleID('Customer'))) {
             Issue::markAsUpdated($issue_id, 'customer action');
         } else {
             if ($sender_usr_id && User::getRoleByUser($sender_usr_id, $prj_id) > User::getRoleID('Customer')) {
                 Issue::markAsUpdated($issue_id, 'staff response');
             } else {
                 Issue::markAsUpdated($issue_id, 'user response');
             }
         }
         History::add($issue_id, $current_usr_id, 'email_sent', 'Outgoing email sent by {user}', array('user' => User::getFullName($current_usr_id)));
     }
     return 1;
 }
Exemplo n.º 3
0
 /**
  * Method used to add a new issue using the normal report form.
  *
  * @return  integer The new issue ID
  */
 public static function createFromPost()
 {
     $keys = array('add_primary_contact', 'attached_emails', 'category', 'contact', 'contact_email', 'contact_extra_emails', 'contact_person_fname', 'contact_person_lname', 'contact_phone', 'contact_timezone', 'contract', 'customer', 'custom_fields', 'description', 'estimated_dev_time', 'group', 'notify_customer', 'notify_senders', 'priority', 'private', 'release', 'severity', 'summary', 'users', 'product', 'product_version', 'expected_resolution_date', 'associated_issues');
     $data = array();
     foreach ($keys as $key) {
         if (isset($_POST[$key])) {
             $data[$key] = $_POST[$key];
         }
     }
     $prj_id = Auth::getCurrentProject();
     $current_usr_id = Auth::getUserID();
     $usr_id = $current_usr_id;
     // if we are creating an issue for a customer, put the
     // main customer contact as the reporter for it
     if (CRM::hasCustomerIntegration($prj_id)) {
         $crm = CRM::getInstance($prj_id);
         $contact_usr_id = User::getUserIDByContactID($data['contact']);
         if (empty($contact_usr_id)) {
             $contact_usr_id = $usr_id;
         }
         $data['reporter'] = $contact_usr_id;
     } else {
         $data['reporter'] = $usr_id;
     }
     $data['msg_id'] = Mail_Helper::generateMessageID();
     $issue_id = self::insertIssue($prj_id, $data);
     if ($issue_id == -1) {
         return -1;
     }
     $has_RR = false;
     $info = User::getNameEmail($usr_id);
     // log the creation of the issue
     History::add($issue_id, $current_usr_id, 'issue_opened', 'Issue opened by {user}', array('user' => User::getFullName($current_usr_id)));
     $clone_iss_id = isset($_POST['clone_iss_id']) ? (int) $_POST['clone_iss_id'] : null;
     if ($clone_iss_id && Access::canCloneIssue($clone_iss_id, $current_usr_id)) {
         History::add($issue_id, $current_usr_id, 'issue_cloned_from', 'Issue cloned from #{issue_id}', array('issue_id' => $clone_iss_id));
         History::add($clone_iss_id, $current_usr_id, 'issue_cloned_to', 'Issue cloned to #{issue_id}', array('issue_id' => $issue_id));
         self::addAssociation($issue_id, $clone_iss_id, $usr_id, true);
     }
     $emails = array();
     if (CRM::hasCustomerIntegration($prj_id)) {
         $customer = $crm->getCustomer($data['customer']);
         $contract = $crm->getContract($data['contract']);
         if (!empty($data['contact_extra_emails']) && count($data['contact_extra_emails']) > 0) {
             $emails = $data['contact_extra_emails'];
         }
         // add the primary contact to the notification list
         if (isset($data['add_primary_contact']) && $data['add_primary_contact'] == 'yes') {
             $contact_email = User::getEmailByContactID($data['contact']);
             if (!empty($contact_email)) {
                 $emails[] = $contact_email;
             }
         }
         // if there are any technical account managers associated with this customer, add these users to the notification list
         $managers = $customer->getEventumAccountManagers();
         foreach ($managers as $manager) {
             $emails[] = $manager['usr_email'];
         }
     }
     // add the reporter to the notification list
     $emails[] = $info['usr_email'];
     $emails = array_unique($emails);
     foreach ($emails as $address) {
         Notification::subscribeEmail($usr_id, $issue_id, $address, Notification::getDefaultActions($issue_id, $address, 'new_issue'));
     }
     // only assign the issue to an user if the associated customer has any technical account managers
     $users = array();
     $has_TAM = false;
     if (CRM::hasCustomerIntegration($prj_id) && count($managers) > 0) {
         foreach ($managers as $manager) {
             if ($manager['cam_type'] == 'intpart') {
                 continue;
             }
             $users[] = $manager['cam_usr_id'];
             self::addUserAssociation($usr_id, $issue_id, $manager['cam_usr_id'], false);
             History::add($issue_id, $usr_id, 'issue_auto_assigned', 'Issue auto-assigned to {assignee} (TAM)', array('assignee' => User::getFullName($manager['cam_usr_id'])));
         }
         $has_TAM = true;
     }
     // now add the user/issue association (aka assignments)
     if (!empty($data['users']) && count($data['users']) > 0) {
         foreach ($data['users'] as $user) {
             $actions = Notification::getDefaultActions($issue_id, User::getEmail($user), 'new_issue');
             Notification::subscribeUser($usr_id, $issue_id, $user, $actions);
             self::addUserAssociation($usr_id, $issue_id, $user);
             if ($user != $usr_id) {
                 $users[] = $user;
             }
         }
     } else {
         // only use the round-robin feature if this new issue was not
         // already assigned to a customer account manager
         if (@count($managers) < 1) {
             $assignee = Round_Robin::getNextAssignee($prj_id);
             // assign the issue to the round robin person
             if (!empty($assignee)) {
                 $users[] = $assignee;
                 self::addUserAssociation($usr_id, $issue_id, $assignee, false);
                 History::add($issue_id, APP_SYSTEM_USER_ID, 'rr_issue_assigned', 'Issue auto-assigned to {assignee} (RR)', array('assignee' => User::getFullName($assignee)));
                 $has_RR = true;
             }
         }
     }
     // set product and version
     if (isset($data['product']) && $data['product'] != '-1') {
         Product::addIssueProductVersion($issue_id, $data['product'], $data['product_version']);
     }
     // process any files being uploaded
     // from ajax upload, attachment file ids
     $iaf_ids = !empty($_POST['iaf_ids']) ? explode(',', $_POST['iaf_ids']) : null;
     // if no iaf_ids passed, perhaps it's old style upload
     // TODO: verify that the uploaded file(s) owner is same as attachment owner.
     if (!$iaf_ids && isset($_FILES['file'])) {
         $iaf_ids = Attachment::addFiles($_FILES['file']);
     }
     if ($iaf_ids) {
         Attachment::attachFiles($issue_id, $usr_id, $iaf_ids, false, 'Files uploaded at issue creation time');
     }
     // need to associate any emails ?
     if (!empty($data['attached_emails'])) {
         $items = explode(',', $data['attached_emails']);
         Support::associate($usr_id, $issue_id, $items);
     }
     // need to notify any emails being converted into issues ?
     if (@count($data['notify_senders']) > 0) {
         $recipients = Notification::notifyEmailConvertedIntoIssue($prj_id, $issue_id, $data['notify_senders'], @$data['customer']);
     } else {
         $recipients = array();
     }
     // need to process any custom fields ?
     if (@count($data['custom_fields']) > 0) {
         foreach ($data['custom_fields'] as $fld_id => $value) {
             Custom_Field::associateIssue($issue_id, $fld_id, $value);
         }
     }
     // also send a special confirmation email to the customer contact
     if (@$data['notify_customer'] == 'yes' && !empty($data['contact'])) {
         $contact = $contract->getContact($data['contact']);
         // also need to pass the list of sender emails already notified,
         // so we can avoid notifying the same person again
         $contact_email = User::getEmailByContactID($data['contact']);
         if (@(!in_array($contact_email, $recipients))) {
             $contact->notifyNewIssue($issue_id);
         }
         // now check for additional emails in contact_extra_emails
         if (@count($data['contact_extra_emails']) > 0) {
             $notification_emails = $data['contact_extra_emails'];
             foreach ($notification_emails as $notification_email) {
                 if (@(!in_array($notification_email, $recipients))) {
                     try {
                         $notification_contact = $crm->getContactByEmail($notification_email);
                         $notification_contact->notifyNewIssue($issue_id);
                     } catch (ContactNotFoundException $e) {
                     }
                 }
             }
         }
     }
     // handle associated issues
     if (isset($data['associated_issues'])) {
         $associated_issues = explode(',', $data['associated_issues']);
         if ($clone_iss_id) {
             $associated_issues[] = $clone_iss_id;
         }
         self::updateAssociatedIssuesRelations($issue_id, $associated_issues);
     }
     Workflow::handleNewIssue($prj_id, $issue_id, $has_TAM, $has_RR);
     // also notify any users that want to receive emails anytime a new issue is created
     Notification::notifyNewIssue($prj_id, $issue_id);
     return $issue_id;
 }
Exemplo n.º 4
0
 /**
  * Method used to send an email notification to users that want
  * to be alerted when new issues are created in the system.
  *
  * @param   integer $prj_id The project ID
  * @param   integer $issue_id The issue ID
  * @param   array   $exclude_list The list of users NOT to notify.
  * @return  void
  */
 public static function notifyNewIssue($prj_id, $issue_id, $exclude_list = array())
 {
     // get all users associated with this project
     $stmt = "SELECT\n                    usr_id,\n                    usr_full_name,\n                    usr_email,\n                    pru_role,\n                    usr_customer_id,\n                    usr_customer_contact_id\n                 FROM\n                    {{%user}},\n                    {{%project_user}}\n                 WHERE\n                    pru_prj_id=? AND\n                    usr_id=pru_usr_id AND\n                    usr_status = 'active' AND\n                    pru_role > ?";
     $params = array($prj_id, User::ROLE_CUSTOMER);
     if (count($exclude_list) > 0) {
         $stmt .= ' AND
                 usr_id NOT IN (' . DB_Helper::buildList($exclude_list) . ')';
         $params = array_merge($params, $exclude_list);
     }
     $res = DB_Helper::getInstance()->getAll($stmt, $params);
     $emails = array();
     foreach ($res as $row) {
         $subscriber = Mail_Helper::getFormattedName($row['usr_full_name'], $row['usr_email']);
         // don't send these emails to customers
         if ($row['pru_role'] == User::ROLE_CUSTOMER || !empty($row['usr_customer_id']) || !empty($row['usr_customer_contact_id'])) {
             continue;
         }
         $prefs = Prefs::get($row['usr_id']);
         if (!empty($prefs['receive_new_issue_email'][$prj_id]) && @$prefs['receive_new_issue_email'][$prj_id] && !in_array($subscriber, $emails)) {
             $emails[] = $subscriber;
         }
     }
     // get assignees
     $stmt = "SELECT\n                    usr_id,\n                    usr_full_name,\n                    usr_email\n                 FROM\n                    {{%user}},\n                    {{%issue_user}}\n                 WHERE\n                    isu_iss_id=? AND\n                    usr_id=isu_usr_id AND\n                    usr_status = 'active'";
     $res = DB_Helper::getInstance()->getAll($stmt, array($issue_id));
     foreach ($res as $row) {
         $subscriber = Mail_Helper::getFormattedName($row['usr_full_name'], $row['usr_email']);
         $prefs = Prefs::get($row['usr_id']);
         if (!empty($prefs['receive_assigned_email'][$prj_id]) && @$prefs['receive_assigned_email'][$prj_id] && !in_array($subscriber, $emails)) {
             $emails[] = $subscriber;
         }
     }
     // get any email addresses from products
     $products = Product::getProductsByIssue($issue_id);
     if (count($products) > 0) {
         foreach ($products as $product) {
             $emails[] = $product['pro_email'];
         }
     }
     // get notification list members
     $emails = array_merge($emails, self::getSubscribedNameEmails($issue_id));
     // get any additional emails
     $emails = array_merge($emails, Workflow::getAdditionalEmailAddresses($prj_id, $issue_id, 'new_issue'));
     $data = Issue::getDetails($issue_id, true);
     $data['attachments'] = Attachment::getList($issue_id);
     // notify new issue to irc channel
     $irc_notice = "New Issue #{$issue_id} (";
     $quarantine = Issue::getQuarantineInfo($issue_id);
     if (!empty($quarantine)) {
         $irc_notice .= 'Quarantined; ';
     }
     $irc_notice .= 'Priority: ' . $data['pri_title'];
     // also add information about the assignee, if any
     $assignment = Issue::getAssignedUsers($issue_id);
     if (count($assignment) > 0) {
         $irc_notice .= '; Assignment: ' . implode(', ', $assignment);
     }
     if (!empty($data['iss_grp_id'])) {
         $irc_notice .= '; Group: ' . Group::getName($data['iss_grp_id']);
     }
     $irc_notice .= '), ';
     if (@isset($data['customer'])) {
         $irc_notice .= $data['customer']['name'] . ', ';
     }
     $irc_notice .= $data['iss_summary'];
     self::notifyIRC($prj_id, $irc_notice, $issue_id, false, false, 'new_issue');
     $data['custom_fields'] = array();
     // empty place holder so notifySubscribers will fill it in with appropriate data for the user
     $subject = ev_gettext('New Issue');
     // generate new Message-ID
     $message_id = Mail_Helper::generateMessageID();
     $headers = array('Message-ID' => $message_id);
     self::notifySubscribers($issue_id, $emails, 'new_issue', $data, $subject, false, false, $headers);
 }