/** * Process all commits from trac repository $repository_id matching issue association commits * * @param int $repository_id */ function processCommits($repository_id) { global $db, $scm_name; $sth = $db->prepare('SELECT * FROM revision WHERE repos=? AND message LIKE ?'); $sth->execute(array($repository_id, '%issue%')); $nissues = $ncommits = 0; while ($commit = $sth->fetch(PDO::FETCH_ASSOC)) { $issues = parseIssueIds($commit['message']); if (!$issues) { echo "Skipping {$commit['rev']} (no issue id in commit message): {$commit['message']}\n"; continue; } $ts = Date_Helper::getDateTime((int) ($commit['time'] / 1000000), 'GMT'); $commit_time = $ts->format('Y-m-d H:i:s'); $files = getRevInfo($repository_id, $commit['rev']); foreach ($issues as $issue_id) { foreach ($files as $file) { TracScm::importCheckin($issue_id, $commit_time, $scm_name, $file, $commit['author'], $commit['message']); $ncommits++; } $nissues++; } } echo "Added {$ncommits} commits to {$nissues} issues\n"; }
function scm_ping($module, $username, $scm_name, $issues, $commit_msg) { // module is per file (svn hook) if (is_array($module)) { $module = null; } // process checkins for each issue foreach ($issues as $issue_id) { // check early if issue exists to report proper message back // workflow needs to know project_id to find out which workflow class to use. $prj_id = Issue::getProjectID($issue_id); if (empty($prj_id)) { echo "issue #{$issue_id} not found\n"; continue; } $files = array(); $nfiles = count($_GET['files']); for ($y = 0; $y < $nfiles; $y++) { $file = array('file' => $_GET['files'][$y], 'old_version' => isset($_GET['old_versions'][$y]) ? $_GET['old_versions'][$y] : null, 'new_version' => isset($_GET['new_versions'][$y]) ? $_GET['new_versions'][$y] : null, 'module' => isset($module) ? $module : $_GET['module'][$y]); $files[] = $file; } $commit_time = Date_Helper::getCurrentDateGMT(); SCM::addCheckins($issue_id, $commit_time, $scm_name, $username, $commit_msg, $files); // print report to stdout of commits so hook could report status back to commiter $details = Issue::getDetails($issue_id); echo "#{$issue_id} - {$details['iss_summary']} ({$details['sta_title']})\n"; } }
/** * Method used to save the login information into a log file. It will be * useful for administrative purposes, so we know which customers were able * to login. * * @param string $email The email associated with the user * @param string $type Whether it was a successful login or not * @param string $extra The reason for not being a successful login */ public static function saveLoginAttempt($email, $type, $extra = false) { $msg = Date_Helper::getCurrentDateGMT() . " - Login attempt by '{$email}' was "; if ($type == 'success') { $msg .= "successful.\n"; } else { $msg .= "not successful because of '{$extra}'.\n"; } file_put_contents(APP_LOGIN_LOG, $msg, FILE_APPEND); }
/** * Method used to get the system-wide default preferences. * * @param array $projects An array of projects this user will have access too. * @return array of the default preferences */ public static function getDefaults($projects = null) { $prefs = array('receive_assigned_email' => array(), 'receive_new_issue_email' => array(), 'timezone' => Date_Helper::getDefaultTimezone(), 'week_firstday' => Date_Helper::getDefaultWeekday(), 'list_refresh_rate' => APP_DEFAULT_REFRESH_RATE, 'email_refresh_rate' => APP_DEFAULT_REFRESH_RATE, 'email_signature' => '', 'auto_append_email_sig' => 'no', 'auto_append_note_sig' => 'no', 'close_popup_windows' => 0); if (is_array($projects)) { foreach ($projects as $prj_id) { $prefs['receive_assigned_email'][$prj_id] = APP_DEFAULT_ASSIGNED_EMAILS; $prefs['receive_new_issue_email'][$prj_id] = APP_DEFAULT_NEW_EMAILS; $prefs['receive_copy_of_own_action'][$prj_id] = APP_DEFAULT_COPY_OF_OWN_ACTION; } } return $prefs; }
public static function saveToken($usr_id, $token) { $sql = 'INSERT INTO {{%api_token}} SET apt_usr_id = ?, apt_created = ?, apt_token = ?'; try { $res = DB_Helper::getInstance()->query($sql, array($usr_id, Date_Helper::getCurrentDateGMT(), $token)); } catch (DbException $e) { return -1; } }
/** * Method used to log the changes made against a specific issue. * * @param integer $iss_id The issue ID * @param integer $usr_id The ID of the user. * @param integer|string $htt_id The type ID of this history event. * @param string $summary The summary of the changes * @param array $context parameters used in summary * @param null $min_role The minimum role that can view this entry. If null will default to role from $htt_id */ public static function add($iss_id, $usr_id, $htt_id, $summary, $context = array(), $min_role = null) { if (!is_numeric($htt_id)) { $htt_id = self::getTypeID($htt_id); } if ($min_role === null) { $min_role = self::getTypeRole($htt_id); } $params = array('his_iss_id' => $iss_id, 'his_usr_id' => $usr_id, 'his_created_date' => Date_Helper::getCurrentDateGMT(), 'his_summary' => $summary, 'his_context' => json_encode($context), 'his_htt_id' => $htt_id, 'his_min_role' => $min_role); $stmt = 'INSERT INTO {{%issue_history}} SET ' . DB_Helper::buildSet($params); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { } }
/** * Method used to update the details of a specific reminder condition. * * @return integer 1 if the update worked, -1 or -2 otherwise */ public static function update() { $stmt = 'UPDATE {{%reminder_level_condition}} SET rlc_last_updated_date=?, rlc_rmf_id=?, rlc_rmo_id=?, rlc_value=?, rlc_comparison_rmf_id = ? WHERE rlc_id=?'; $params = array(Date_Helper::getCurrentDateGMT(), $_POST['field'], $_POST['operator'], @$_POST['value'], @$_POST['comparison_field'], $_POST['id']); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return -1; } return 1; }
public static function addPartnerToIssue($iss_id, $par_code) { $current_partners = self::getPartnerCodesByIssue($iss_id); if (!in_array($par_code, $current_partners)) { $params = array($iss_id, $par_code, Date_Helper::getCurrentDateGMT()); $sql = 'INSERT INTO {{%issue_partner}} SET ipa_iss_id = ?, ipa_par_code = ?, ipa_created_date = ?'; try { DB_Helper::getInstance()->query($sql, $params); } catch (DbException $e) { return false; } $backend = self::getBackend($par_code); $backend->issueAdded($iss_id); $usr_id = Auth::getUserID(); History::add($iss_id, $usr_id, 'partner_added', "Partner '{partner}' added to issue by {user}", array('partner' => $backend->getName(), 'user' => User::getFullName($usr_id))); } return true; }
/** * Method used to add a new resolution by using the administrative * interface of the system. * * @return integer 1 if the update worked, -1 or -2 otherwise */ public static function insert() { if (Validation::isWhitespace($_POST['title'])) { return -2; } $stmt = 'INSERT INTO {{%resolution}} ( res_title, res_rank, res_created_date ) VALUES ( ?, ?, ? )'; $params = array($_POST['title'], $_POST['rank'], Date_Helper::getCurrentDateGMT()); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return -1; } return 1; }
/** * Generates the workload by time period graph. * * @param string $type */ public function WorkloadTimePeriodGraph($type) { $usr_id = Auth::getUserID(); // get timezone of current user $user_prefs = Prefs::get($usr_id); if ($type == 'email') { $data = Report::getEmailWorkloadByTimePeriod($user_prefs['timezone'], true); $graph_title = ev_gettext('Email by Time Period'); $event_type = ev_gettext('emails'); } else { $data = Report::getWorkloadByTimePeriod($user_prefs['timezone'], true); $graph_title = ev_gettext('Workload by Time Period'); $event_type = ev_gettext('actions'); } // TRANSLATORS: %s = Timezone name $xtitle = ev_gettext('Hours (%s)', Date_Helper::getTimezoneShortNameByUser($usr_id)); // rebuild data for phplot format $plotData = array(); $legends = array(); $i = 1; foreach ($data as $performer => $values) { foreach ($values as $hour => $value) { $plotData[(int) $hour][0] = $hour; $plotData[(int) $hour][$i] = $value; } $legends[$i] = ucfirst($performer) . ' ' . $event_type; $i++; } $plot = $this->create(900, 350); $plot->SetImageBorderType('plain'); $plot->SetPlotType('bars'); $plot->SetDataType('text-data'); $plot->SetDataValues($plotData); $plot->SetTitle($graph_title); $plot->SetLegend($legends); $plot->SetYTitle($event_type); $plot->SetXTitle($xtitle); $plot->SetXTickLabelPos('none'); $plot->SetXTickPos('none'); $plot->SetYDataLabelPos('plotin'); $plot->SetYLabelType('printf', '%.0f%%'); $plot->group_frac_width = 1; $plot->DrawGraph(); }
/** * Method used to add a new user to the system. * * @param array $user The array of user information * @return integer 1 if the update worked, -1 otherwise */ public static function insert($user) { $projects = array(); foreach ($user['role'] as $prj_id => $role) { if ($role < 1) { continue; } $projects[] = $prj_id; } $params = array(isset($user['customer_id']) ? $user['customer_id'] : null, isset($user['contact_id']) ? $user['contact_id'] : null, Date_Helper::getCurrentDateGMT(), Auth::hashPassword($user['password']), $user['full_name'], $user['email'], !empty($user['grp_id']) ? $user['grp_id'] : null, $user['external_id'], isset($user['par_code']) ? $user['par_code'] : null); $stmt = 'INSERT INTO {{%user}} ( usr_customer_id, usr_customer_contact_id, usr_created_date, usr_password, usr_full_name, usr_email, usr_grp_id, usr_external_id, usr_par_code ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )'; try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return -1; } $new_usr_id = DB_Helper::get_last_insert_id(); // add the project associations! $projects = array(); foreach ($user['role'] as $prj_id => $role) { if ($role < 1) { continue; } Project::associateUser($prj_id, $new_usr_id, $role); $projects[] = $prj_id; } Prefs::set($new_usr_id, Prefs::getDefaults($projects)); // send email to user Notification::notifyNewUser($new_usr_id, $user['password']); return $new_usr_id; }
/** * Returns a list of drafts associated with an issue. * * @param integer $issue_id The ID of the issue. * @param boolean $show_all If all draft statuses should be shown * @return array An array of drafts. */ public static function getList($issue_id, $show_all = false) { $stmt = "SELECT\n emd_id,\n emd_usr_id,\n emd_subject,\n emd_updated_date,\n emd_unknown_user,\n emd_status\n FROM\n {{%email_draft}}\n WHERE\n emd_iss_id=?\n"; $params = array($issue_id); if ($show_all == false) { $stmt .= "AND emd_status = 'pending'\n"; } $stmt .= 'ORDER BY emd_id'; try { $res = DB_Helper::getInstance()->getAll($stmt, $params); } catch (DbException $e) { return ''; } foreach ($res as &$row) { $row['emd_updated_date'] = Date_Helper::getFormattedDate($row['emd_updated_date']); if (!empty($row['emd_unknown_user'])) { $row['from'] = $row['emd_unknown_user']; } else { $row['from'] = User::getFromHeader($row['emd_usr_id']); } list($row['to']) = self::getEmailRecipients($row['emd_id']); if (empty($row['to'])) { $row['to'] = 'Notification List'; } } return $res; }
/** * Method used to add a FAQ entry to the system. * * @return integer 1 if the insert worked, -1 otherwise */ public static function insert() { if (Validation::isWhitespace($_POST['title'])) { return -2; } if (Validation::isWhitespace($_POST['message'])) { return -3; } $stmt = 'INSERT INTO {{%faq}} ( faq_prj_id, faq_usr_id, faq_created_date, faq_title, faq_message, faq_rank ) VALUES ( ?, ?, ?, ?, ?, ? )'; $params = array($_POST['project'], Auth::getUserID(), Date_Helper::getCurrentDateGMT(), $_POST['title'], $_POST['message'], $_POST['rank']); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return -1; } $new_faq_id = DB_Helper::get_last_insert_id(); if (isset($_POST['support_levels']) && count($_POST['support_levels']) > 0) { // now populate the faq-support level mapping table foreach ($_POST['support_levels'] as $support_level_id) { self::addSupportLevelAssociation($new_faq_id, $support_level_id); } } return 1; }
/** * 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; }
/** * Method used to remotely record a time tracking entry. * * @param integer $issue_id The issue ID * @param integer $usr_id The user ID * @param integer $cat_id The time tracking category ID * @param string $summary The summary of the work entry * @param integer $time_spent The time spent in minutes * @return integer 1 if the insert worked, -1 otherwise */ public static function recordRemoteTimeEntry($issue_id, $usr_id, $cat_id, $summary, $time_spent) { $stmt = 'INSERT INTO {{%time_tracking}} ( ttr_ttc_id, ttr_iss_id, ttr_usr_id, ttr_created_date, ttr_time_spent, ttr_summary ) VALUES ( ?, ?, ?, ?, ?, ? )'; $params = array($cat_id, $issue_id, $usr_id, Date_Helper::getCurrentDateGMT(), $time_spent, $summary); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return -1; } Issue::markAsUpdated($issue_id); History::add($issue_id, $usr_id, 'remote_time_added', 'Time tracking entry submitted remotely by {user}', array('user' => User::getFullName($usr_id))); return 1; }
private function processResult(&$data, $date_field, $issue_field) { $timezone = Date_Helper::getPreferredTimezone($this->usr_id); foreach ($data as &$res) { if (!Issue::canAccess($res[$issue_field], $this->usr_id)) { continue; } $res['customer'] = null; if ($this->crm) { try { $customer = $this->crm->getCustomer(Issue::getCustomerID($res[$issue_field])); $res['customer'] = $customer->getName(); } catch (CRMException $e) { } } $res['date'] = Date_Helper::getFormattedDate($res[$date_field], $timezone); // need to decode From:, To: mail headers if (isset($res['sup_from'])) { $res['sup_from'] = Mime_Helper::fixEncoding($res['sup_from']); } if (isset($res['sup_to'])) { $res['sup_to'] = Mime_Helper::fixEncoding($res['sup_to']); } } }
/** * Returns the status of a quarantine. * * @param integer $issue_id The issue ID * @return integer Indicates what the current state of quarantine is. */ public static function getQuarantineInfo($issue_id) { $stmt = 'SELECT iqu_status, iqu_expiration FROM {{%issue_quarantine}} WHERE iqu_iss_id = ? AND (iqu_expiration > ? OR iqu_expiration IS NULL)'; try { $res = DB_Helper::getInstance()->getRow($stmt, array($issue_id, Date_Helper::getCurrentDateGMT())); } catch (DbException $e) { return array(); } if (!empty($res['iqu_expiration'])) { $expiration_ts = Date_Helper::getUnixTimestamp($res['iqu_expiration'], Date_Helper::getDefaultTimezone()); $res['time_till_expiration'] = Date_Helper::getFormattedDateDiff($expiration_ts, time()); } return $res; }
/** * Format "On ... Wrote:" reply preamble. Helper for translations. * * @param string $date * @param string $sender * @return string */ public static function formatReplyPreamble($date, $sender) { $date = Date_Helper::getFormattedDate($date); // TRANSLATORS: %1: date, %2: sender $line = ev_gettext('On %1$s, %2$s wrote:', $date, $sender); return "\n\n\n{$line}\n>\n"; }
/** * Method used to print a confirmation prompt with the current details * of the given issue. The $command parameter can be used to determine what type of * confirmation to show to the user. * * @param RemoteApi $client The connection resource * @param array $auth Array of authentication information (email, password) * @param integer $issue_id The issue ID * @param string $args The arguments passed to this script */ public static function promptConfirmation($client, $auth, $issue_id, $args) { // this is needed to prevent multiple confirmations from being shown to the user $GLOBALS['_displayed_confirmation'] = true; // get summary, customer status and assignment of issue, then show confirmation prompt to user $details = $client->getSimpleIssueDetails($auth[0], $auth[1], $issue_id); switch ($args[2]) { case 'convert-note': case 'cn': $note_details = self::getNote($client, $auth, $issue_id, $args[3]); $not_created_date = Date_Helper::getFormattedDate($note_details['not_created_date']); $msg = "These are the current details for issue #{$issue_id}, note #" . $args[3] . ":\n" . ' Date: ' . $not_created_date . "\n" . ' From: ' . $note_details['not_from'] . "\n" . ' Title: ' . $note_details['not_title'] . "\n" . 'Are you sure you want to convert this note into a ' . $args[4] . '?'; break; default: $msg = "These are the current details for issue #{$issue_id}:\n" . ' Summary: ' . $details['summary'] . "\n"; if (@(!empty($details['customer']))) { $msg .= ' Customer: ' . $details['customer'] . "\n"; } $msg .= ' Status: ' . $details['status'] . "\n" . ' Assignment: ' . $details['assignments'] . "\n" . ' Auth. Repliers: ' . $details['authorized_names'] . "\n" . 'Are you sure you want to change this issue?'; } $ret = CLI_Misc::prompt($msg, 'y'); if (strtolower($ret) != 'y') { exit; } }
/** * Adds a quick note for the specified customer. * * @param integer $prj_id The project ID * @param integer $customer_id The id of the customer. * @param string $note The note to add. * @return int */ public static function insertNote($prj_id, $customer_id, $note) { $stmt = 'INSERT INTO {{%customer_note}} ( cno_prj_id, cno_customer_id, cno_created_date, cno_updated_date, cno_note ) VALUES ( ?, ?, ?, ?, ? )'; try { DB_Helper::getInstance()->query($stmt, array($prj_id, $customer_id, Date_Helper::getCurrentDateGMT(), Date_Helper::getCurrentDateGMT(), $note)); } catch (DbException $e) { return -1; } return 1; }
} // print out emails $developer = $_REQUEST['developer']; $prj_id = Auth::getCurrentProject(); $options = array('separate_closed' => @$_REQUEST['separate_closed'], 'separate_not_assigned_to_user' => @$_REQUEST['separate_not_assigned_to_user'], 'ignore_statuses' => @$_REQUEST['ignore_statuses'], 'show_per_issue' => !empty($_REQUEST['show_per_issue']), 'separate_no_time' => !empty($_REQUEST['separate_no_time'])); $data = Report::getWeeklyReport($developer, $prj_id, $dates[0], $dates[1], $options); // order issues by time spent on them if (isset($_REQUEST['show_per_issue'])) { $sort_function = function ($a, $b) { if ($a['it_spent'] == $b['it_spent']) { return 0; } return $a['it_spent'] < $b['it_spent'] ? 1 : -1; }; usort($data['issues']['closed'], $sort_function); usort($data['issues']['other'], $sort_function); usort($data['issues']['not_mine'], $sort_function); } $tpl->assign('data', $data); } if (empty($_REQUEST['week'])) { $tpl->assign('week', Date_Helper::getCurrentWeek()); } else { $tpl->assign('week', $_REQUEST['week']); } if (empty($_REQUEST['developer'])) { $tpl->assign('developer', Auth::getUserID()); } else { $tpl->assign('developer', $_REQUEST['developer']); } $tpl->displayTemplate();
/** * Method used to add a new project to the system. * * @return integer 1 if the update worked, -1 or -2 otherwise */ public static function insert() { if (Validation::isWhitespace($_POST['title'])) { return -2; } $stmt = 'INSERT INTO {{%project}} ( prj_created_date, prj_title, prj_status, prj_lead_usr_id, prj_initial_sta_id, prj_outgoing_sender_name, prj_outgoing_sender_email, prj_mail_aliases, prj_remote_invocation, prj_customer_backend, prj_workflow_backend ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? )'; try { DB_Helper::getInstance()->query($stmt, array(Date_Helper::getCurrentDateGMT(), $_POST['title'], $_POST['status'], $_POST['lead_usr_id'], $_POST['initial_status'], $_POST['outgoing_sender_name'], $_POST['outgoing_sender_email'], $_POST['mail_aliases'], $_POST['remote_invocation'], $_POST['customer_backend'], $_POST['workflow_backend'])); } catch (DbException $e) { return -1; } $new_prj_id = DB_Helper::get_last_insert_id(); foreach ($_POST['users'] as $user) { if ($user == $_POST['lead_usr_id']) { $role_id = User::getRoleID('Manager'); } else { $role_id = User::getRoleID('Standard User'); } self::associateUser($new_prj_id, $user, $role_id); } foreach ($_POST['statuses'] as $sta_id) { Status::addProjectAssociation($sta_id, $new_prj_id); } Display_Column::setupNewProject($new_prj_id); // insert default timetracking categories Time_Tracking::addProjectDefaults($new_prj_id); return 1; }
// also auto pre-fill the customer contact text fields if (CRM::hasCustomerIntegration($prj_id)) { $sender_email = Mail_Helper::getEmailAddress($email_details['sup_from']); try { $contact = $crm->getContactByEmail($sender_email); $tpl->assign('contact_details', $contact->getDetails()); } catch (CRMException $e) { } } } } } $tpl->assign(array('cats' => Category::getAssocList($prj_id), 'priorities' => Priority::getAssocList($prj_id), 'severities' => Severity::getList($prj_id), 'users' => Project::getUserAssocList($prj_id, 'active', User::getRoleID('Customer')), 'releases' => Release::getAssocList($prj_id), 'custom_fields' => Custom_Field::getListByProject($prj_id, 'report_form'), 'max_attachment_size' => Attachment::getMaxAttachmentSize(), 'max_attachment_bytes' => Attachment::getMaxAttachmentSize(true), 'field_display_settings' => Project::getFieldDisplaySettings($prj_id), 'groups' => Group::getAssocList($prj_id), 'products' => Product::getList(false))); $prefs = Prefs::get($usr_id); $tpl->assign('user_prefs', $prefs); $tpl->assign('zones', Date_Helper::getTimezoneList()); if (Auth::getCurrentRole() == User::getRoleID('Customer')) { $crm = CRM::getInstance(Auth::getCurrentProject()); $customer_contact_id = User::getCustomerContactID($usr_id); $contact = $crm->getContact($customer_contact_id); $customer_id = Auth::getCurrentCustomerID(); $customer = $crm->getCustomer($customer_id); // TODOCRM: Pull contacts via ajax when user selects contract $tpl->assign(array('customer_id' => $customer_id, 'contact_id' => $customer_contact_id, 'customer' => $customer, 'contact' => $contact)); } $clone_iss_id = isset($_GET['clone_iss_id']) ? (int) $_GET['clone_iss_id'] : null; if ($clone_iss_id && Access::canCloneIssue($clone_iss_id, $usr_id)) { $tpl->assign(Issue::getCloneIssueTemplateVariables($clone_iss_id)); } else { $tpl->assign('defaults', $_REQUEST); }
/** * Returns data on when support emails are sent/received. * * @param string $timezone Timezone to display time in in addition to GMT * @param boolean $graph If the data should be formatted for use in a graph. Default false * @return array An array of data. */ public static function getEmailWorkloadByTimePeriod($timezone, $graph = false) { // get total counts $stmt = 'SELECT hour(sup_date) AS time_period, count(*) as events FROM {{%support_email}} GROUP BY time_period'; try { $total = DB_Helper::getInstance()->fetchAssoc($stmt); } catch (DbException $e) { return array(); } // get all developer email addresses $users = User::getActiveAssocList(Auth::getCurrentProject(), User::getRoleID('customer')); $emails = array(); foreach ($users as $usr_id => $usr_full_name) { $emails[] = User::getFromHeader($usr_id); } // get number of support emails from developers $list = DB_Helper::buildList($emails); $stmt = "SELECT\n hour(sup_date) AS time_period,\n count(*) as events\n FROM\n {{%support_email}}\n WHERE\n sup_from IN({$list})\n GROUP BY\n time_period"; try { $dev_stats = DB_Helper::getInstance()->fetchAssoc($stmt, $emails); } catch (DbException $e) { return array(); } // get total number of developer and customer events and build cust_stats array $dev_count = 0; $cust_count = 0; $cust_stats = array(); for ($i = 0; $i < 24; $i++) { if (empty($dev_stats[$i])) { $dev_stats[$i] = 0; } $cust_stats[$i] = @$total[$i] - @$dev_stats[$i]; $cust_count += @$total[$i] - @$dev_stats[$i]; $dev_count += @$dev_stats[$i]; } $data = array(); $sort_values = array(); for ($i = 0; $i < 24; $i++) { // convert to the users time zone $dt = Date_Helper::getDateTime(mktime($i, 0, 0), 'GMT'); $gmt_time = $dt->format('H:i'); $dt->setTimeZone(new DateTimeZone($timezone)); $hour = $dt->format('H'); $user_time = $dt->format('H:i'); if ($graph) { $data['developer'][$hour] = ''; $data['customer'][$hour] = ''; } else { $data[$i]['display_time_gmt'] = $gmt_time; $data[$i]['display_time_user'] = $user_time; } // use later to find highest value $sort_values['developer'][$i] = $dev_stats[$i]; $sort_values['customer'][$i] = $cust_stats[$i]; if ($graph) { if ($dev_count == 0) { $data['developer'][$hour] = 0; } else { $data['developer'][$hour] = $dev_stats[$i] / $dev_count * 100; } if ($cust_count == 0) { $data['customer'][$hour] = 0; } else { $data['customer'][$hour] = $cust_stats[$i] / $cust_count * 100; } } else { $data[$i]['developer']['count'] = $dev_stats[$i]; if ($dev_count == 0) { $data[$i]['developer']['percentage'] = 0; } else { $data[$i]['developer']['percentage'] = $dev_stats[$i] / $dev_count * 100; } $data[$i]['customer']['count'] = $cust_stats[$i]; if ($cust_count == 0) { $data[$i]['customer']['percentage'] = 0; } else { $data[$i]['customer']['percentage'] = $cust_stats[$i] / $cust_count * 100; } } } if (!$graph) { // get the highest action times foreach ($sort_values as $performer => $values) { arsort($values); reset($values); $data[key($values)][$performer]['rank'] = 1; } } return $data; }
// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | // | GNU General Public License for more details. | // | | // | You should have received a copy of the GNU General Public License | // | along with this program; if not, write to: | // | | // | Free Software Foundation, Inc. | // | 51 Franklin Street, Suite 330 | // | Boston, MA 02110-1301, USA. | // +----------------------------------------------------------------------+ // | Authors: Bryan Alsdorf <*****@*****.**> | // +----------------------------------------------------------------------+ require_once dirname(__FILE__) . '/../../init.php'; $tpl = new Template_Helper(); $tpl->setTemplate('reports/workload_time_period.tpl.html'); Auth::checkAuthentication(APP_COOKIE); $usr_id = Auth::getUserID(); if (!Access::canAccessReports(Auth::getUserID())) { echo 'Invalid role'; exit; } $prj_id = Auth::getCurrentProject(); // get timezone of current user $user_prefs = Prefs::get($usr_id); if (@$_GET['type'] == 'email') { $data = Report::getEmailWorkloadByTimePeriod(@$user_prefs['timezone']); } else { $data = Report::getWorkloadByTimePeriod(@$user_prefs['timezone']); } $tpl->assign(array('data' => $data, 'type' => @$_GET['type'], 'user_tz' => Date_Helper::getTimezoneShortNameByUser($usr_id))); $tpl->displayTemplate();
/** * Method used to add an attachment to the database. * * @param integer $issue_id The issue ID * @param integer $usr_id The user ID * @param string $description The description for this new attachment * @param boolean $internal_only Whether this attachment is supposed to be internal only or not * @param string $unknown_user The email of the user who originally sent this email, who doesn't have an account. * @param integer $associated_note_id The note ID that these attachments should be associated with * @return integer The new attachment ID */ public static function add($issue_id, $usr_id, $description, $internal_only = false, $unknown_user = null, $associated_note_id = null) { if ($internal_only) { $attachment_status = 'internal'; } else { $attachment_status = 'public'; } $params = array('iat_iss_id' => $issue_id, 'iat_usr_id' => $usr_id, 'iat_created_date' => Date_Helper::getCurrentDateGMT(), 'iat_description' => $description, 'iat_status' => $attachment_status); if ($unknown_user) { $params['iat_unknown_user'] = $unknown_user; } if ($associated_note_id) { $params['iat_not_id'] = $associated_note_id; } $stmt = 'INSERT INTO {{%issue_attachment}} SET ' . DB_Helper::buildSet($params); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return false; } return DB_Helper::get_last_insert_id(); }
/** * Converts a note to a draft or an email * * @param int $note_id The id of the note * @param string $target What the note should be converted too (email, etc) * @param bool $authorize_sender If $authorize_sender If the sender should be added to authorized senders list. * @return int */ public static function convertNote($note_id, $target, $authorize_sender = false) { $issue_id = self::getIssueID($note_id); $email_account_id = Email_Account::getEmailAccount(); $blocked_message = self::getBlockedMessage($note_id); $unknown_user = self::getUnknownUser($note_id); $structure = Mime_Helper::decode($blocked_message, true, true); $body = $structure->body; $sender_email = strtolower(Mail_Helper::getEmailAddress($structure->headers['from'])); $current_usr_id = Auth::getUserID(); if ($target == 'email') { if (Mime_Helper::hasAttachments($structure)) { $has_attachments = 1; } else { $has_attachments = 0; } list($blocked_message, $headers) = Mail_Helper::rewriteThreadingHeaders($issue_id, $blocked_message, @$structure->headers); $t = array('issue_id' => $issue_id, 'ema_id' => $email_account_id, 'message_id' => @$structure->headers['message-id'], 'date' => Date_Helper::getCurrentDateGMT(), 'from' => @$structure->headers['from'], 'to' => @$structure->headers['to'], 'cc' => @$structure->headers['cc'], 'subject' => @$structure->headers['subject'], 'body' => @$body, 'full_email' => @$blocked_message, 'has_attachment' => $has_attachments, 'headers' => $headers); // need to check for a possible customer association if (!empty($structure->headers['from'])) { $details = Email_Account::getDetails($email_account_id); // check from the associated project if we need to lookup any customers by this email address if (CRM::hasCustomerIntegration($details['ema_prj_id'])) { $crm = CRM::getInstance($details['ema_prj_id']); // check for any customer contact association try { $contact = $crm->getContactByEmail($sender_email); $issue_contract = $crm->getContract(Issue::getContractID($issue_id)); if ($contact->canAccessContract($issue_contract)) { $t['customer_id'] = $issue_contract->getCustomerID(); } } catch (CRMException $e) { } } } if (empty($t['customer_id'])) { $update_type = 'staff response'; $t['customer_id'] = null; } else { $update_type = 'customer action'; } $res = Support::insertEmail($t, $structure, $sup_id); if ($res != -1) { Support::extractAttachments($issue_id, $structure); // notifications about new emails are always external $internal_only = false; // special case when emails are bounced back, so we don't want to notify the customer about those if (Notification::isBounceMessage($sender_email)) { $internal_only = true; } Notification::notifyNewEmail($current_usr_id, $issue_id, $t, $internal_only, false, '', $sup_id); Issue::markAsUpdated($issue_id, $update_type); self::remove($note_id, false); History::add($issue_id, $current_usr_id, 'note_converted_email', 'Note converted to e-mail (from: {from}) by {user}', array('from' => @$structure->headers['from'], 'user' => User::getFullName($current_usr_id))); // now add sender as an authorized replier if ($authorize_sender) { Authorized_Replier::manualInsert($issue_id, @$structure->headers['from']); } } return $res; } // save message as a draft $res = Draft::saveEmail($issue_id, $structure->headers['to'], $structure->headers['cc'], $structure->headers['subject'], $body, false, $unknown_user); // remove the note, if the draft was created successfully if ($res) { self::remove($note_id, false); $usr_id = $current_usr_id; History::add($issue_id, $usr_id, 'note_converted_draft', 'Note converted to draft (from: {from}) by {user}', array('from' => @$structure->headers['from'], 'user' => User::getFullName($current_usr_id))); } return $res; }
/** * Method used to get the list of issues to be displayed in the grid layout. * * @param array $options The search parameters * @return string The where clause */ public static function buildWhereClause($options) { $usr_id = Auth::getUserID(); $prj_id = Auth::getCurrentProject(); $role_id = User::getRoleByUser($usr_id, $prj_id); $usr_details = User::getDetails($usr_id); $stmt = ' AND iss_usr_id = usr_id'; if ($role_id == User::getRoleID('Customer')) { $crm = CRM::getInstance($prj_id); $contact = $crm->getContact($usr_details['usr_customer_contact_id']); $stmt .= " AND iss_customer_contract_id IN('" . implode("','", $contact->getContractIDS()) . "')"; $stmt .= " AND iss_customer_id ='" . Auth::getCurrentCustomerID() . "'"; } elseif ($role_id == User::getRoleID('Reporter') && Project::getSegregateReporters($prj_id)) { $stmt .= " AND (\n iss_usr_id = {$usr_id} OR\n iur_usr_id = {$usr_id}\n )"; } if (!empty($usr_details['usr_par_code'])) { // restrict partners $stmt .= " AND ipa_par_code = '" . Misc::escapeString($usr_details['usr_par_code']) . "'"; } if (!empty($options['users'])) { $stmt .= " AND (\n"; if (stristr($options['users'], 'grp') !== false) { $chunks = explode(':', $options['users']); $stmt .= 'iss_grp_id = ' . Misc::escapeInteger($chunks[1]); } else { if ($options['users'] == '-1') { $stmt .= 'isu_usr_id IS NULL'; } elseif ($options['users'] == '-2') { $stmt .= 'isu_usr_id IS NULL OR isu_usr_id=' . $usr_id; } elseif ($options['users'] == '-3') { $stmt .= 'isu_usr_id = ' . $usr_id . ' OR iss_grp_id = ' . User::getGroupID($usr_id); } elseif ($options['users'] == '-4') { $stmt .= 'isu_usr_id IS NULL OR isu_usr_id = ' . $usr_id . ' OR iss_grp_id = ' . User::getGroupID($usr_id); } else { $stmt .= 'isu_usr_id =' . Misc::escapeInteger($options['users']); } } $stmt .= ')'; } if (!empty($options['reporter'])) { $stmt .= ' AND iss_usr_id = ' . Misc::escapeInteger($options['reporter']); } if (!empty($options['show_authorized_issues'])) { $stmt .= " AND (iur_usr_id={$usr_id})"; } if (!empty($options['show_notification_list_issues'])) { $stmt .= " AND (sub_usr_id={$usr_id})"; } if (!empty($options['keywords'])) { $stmt .= " AND (\n"; if ($options['search_type'] == 'all_text' && APP_ENABLE_FULLTEXT) { $stmt .= 'iss_id IN(' . implode(', ', self::getFullTextIssues($options)) . ')'; } elseif ($options['search_type'] == 'customer' && CRM::hasCustomerIntegration($prj_id)) { // check if the user is trying to search by customer name / email $crm = CRM::getInstance($prj_id); $customer_ids = $crm->getCustomerIDsByString($options['keywords'], true); if (count($customer_ids) > 0) { $stmt .= ' iss_customer_id IN (' . implode(', ', $customer_ids) . ')'; } else { // no results, kill query $stmt .= ' iss_customer_id = -1'; } } else { $stmt .= '(' . Misc::prepareBooleanSearch('iss_summary', $options['keywords']); $stmt .= ' OR ' . Misc::prepareBooleanSearch('iss_description', $options['keywords']) . ')'; } $stmt .= "\n) "; } if (!empty($options['customer_id'])) { $stmt .= " AND iss_customer_id='" . Misc::escapeString($options['customer_id']) . "'"; } if (!empty($options['priority'])) { $stmt .= ' AND iss_pri_id=' . Misc::escapeInteger($options['priority']); } if (!empty($options['status'])) { $stmt .= ' AND iss_sta_id=' . Misc::escapeInteger($options['status']); } if (!empty($options['category'])) { if (!is_array($options['category'])) { $options['category'] = array($options['category']); } $stmt .= ' AND iss_prc_id IN(' . implode(', ', Misc::escapeInteger($options['category'])) . ')'; } if (!empty($options['hide_closed'])) { $stmt .= ' AND sta_is_closed=0'; } if (!empty($options['release'])) { $stmt .= ' AND iss_pre_id = ' . Misc::escapeInteger($options['release']); } if (!empty($options['product'])) { $stmt .= ' AND ipv_pro_id = ' . Misc::escapeInteger($options['product']); } // now for the date fields $date_fields = array('created_date', 'updated_date', 'last_response_date', 'first_response_date', 'closed_date'); foreach ($date_fields as $field_name) { if (!empty($options[$field_name])) { switch ($options[$field_name]['filter_type']) { case 'greater': $stmt .= " AND iss_{$field_name} >= '" . Misc::escapeString($options[$field_name]['start']) . "'"; break; case 'less': $stmt .= " AND iss_{$field_name} <= '" . Misc::escapeString($options[$field_name]['start']) . "'"; break; case 'between': $stmt .= " AND iss_{$field_name} BETWEEN '" . Misc::escapeString($options[$field_name]['start']) . "' AND '" . Misc::escapeString($options[$field_name]['end']) . "'"; break; case 'null': $stmt .= " AND iss_{$field_name} IS NULL"; break; case 'in_past': if (strlen($options[$field_name]['time_period']) == 0) { $options[$field_name]['time_period'] = 0; } $stmt .= " AND (UNIX_TIMESTAMP('" . Date_Helper::getCurrentDateGMT() . "') - UNIX_TIMESTAMP(iss_{$field_name})) <= (" . Misc::escapeInteger($options[$field_name]['time_period']) . '*3600)'; break; } } } // custom fields if (is_array($options['custom_field']) && count($options['custom_field']) > 0) { foreach ($options['custom_field'] as $fld_id => $search_value) { if (empty($search_value)) { continue; } $field = Custom_Field::getDetails($fld_id); $fld_db_name = Custom_Field::getDBValueFieldNameByType($field['fld_type']); if ($field['fld_type'] == 'date' && (empty($search_value['Year']) || empty($search_value['Month']) || empty($search_value['Day']))) { continue; } if ($field['fld_type'] == 'integer' && empty($search_value['value'])) { continue; } if ($field['fld_type'] == 'multiple') { $search_value = Misc::escapeString($search_value); foreach ($search_value as $cfo_id) { $cfo_id = Misc::escapeString($cfo_id); $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . '.icf_iss_id = iss_id'; $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . ".icf_fld_id = {$fld_id}"; $stmt .= " AND\n cf" . $fld_id . '_' . $cfo_id . '.' . $fld_db_name . " = '{$cfo_id}'"; } } elseif ($field['fld_type'] == 'date') { if (empty($search_value['Year']) || empty($search_value['Month']) || empty($search_value['Day'])) { continue; } $search_value = $search_value['Year'] . '-' . $search_value['Month'] . '-' . $search_value['Day']; $stmt .= " AND\n (iss_id = cf" . $fld_id . '.icf_iss_id AND cf' . $fld_id . '.' . $fld_db_name . " = '" . Misc::escapeString($search_value) . "')"; } elseif ($field['fld_type'] == 'integer') { $value = $search_value['value']; switch ($search_value['filter_type']) { case 'ge': $cmp = '>='; break; case 'le': $cmp = '<='; break; case 'gt': $cmp = '>'; break; case 'lt': $cmp = '<'; break; default: $cmp = '='; break; } $stmt .= " AND\n (iss_id = cf" . $fld_id . '.icf_iss_id'; $stmt .= " AND\n cf" . $fld_id . ".icf_fld_id = {$fld_id}"; $stmt .= ' AND cf' . $fld_id . '.' . $fld_db_name . $cmp . Misc::escapeString($value) . ')'; } else { $stmt .= " AND\n (iss_id = cf" . $fld_id . '.icf_iss_id'; $stmt .= " AND\n cf" . $fld_id . ".icf_fld_id = {$fld_id}"; if ($field['fld_type'] == 'combo') { $stmt .= ' AND cf' . $fld_id . '.' . $fld_db_name . " IN('" . implode("', '", Misc::escapeString($search_value)) . "')"; } else { $stmt .= ' AND cf' . $fld_id . '.' . $fld_db_name . " LIKE '%" . Misc::escapeString($search_value) . "%'"; } $stmt .= ')'; } } } // clear cached full-text values if we are not searching fulltext anymore if (APP_ENABLE_FULLTEXT && @$options['search_type'] != 'all_text') { Session::set('fulltext_string', ''); Session::set('fulltext_issues', ''); } return $stmt; }
/** * Method used to add a news entry to the system. * * @return integer 1 if the insert worked, -1 otherwise */ public static function insert() { if (Validation::isWhitespace($_POST['title'])) { return -2; } if (Validation::isWhitespace($_POST['message'])) { return -3; } $stmt = 'INSERT INTO {{%news}} ( nws_usr_id, nws_created_date, nws_title, nws_message, nws_status ) VALUES ( ?, ?, ?, ?, ? )'; $params = array(Auth::getUserID(), Date_Helper::getCurrentDateGMT(), $_POST['title'], $_POST['message'], $_POST['status']); try { DB_Helper::getInstance()->query($stmt, $params); } catch (DbException $e) { return -1; } $new_news_id = DB_Helper::get_last_insert_id(); // now populate the project-news mapping table foreach ($_POST['projects'] as $prj_id) { self::addProjectAssociation($new_news_id, $prj_id); } return 1; }
// check if user role is above "Standard User" if (User::getRoleByUser($usr_id, Issue::getProjectID($issue_id)) < User::getRoleID('Standard User')) { die('Forbidden'); } // check if user can acess the issue if (!Issue::canAccess($issue_id, $usr_id)) { die('Forbidden'); } switch ($field_name) { case 'expected_resolution_date': $day = Misc::escapeInteger($_POST['day']); $month = Misc::escapeInteger($_POST['month']); $year = Misc::escapeInteger($_POST['year']); if ($day == 0 && $month == 1 && $year == 0) { // clear button $date = null; } else { $date = sprintf('%04d-%02d-%02d', $year, $month, $day); } $res = Issue::setExpectedResolutionDate($issue_id, $date); if ($res == -1) { die('Update failed'); } if ($date !== null) { echo Date_Helper::getSimpleDate($date, false); } break; default: die("Object type '{$field_name}' not supported"); break; }