/** * Close tickets in a pending state for a specific amount of time * * @param object $job \Components\Cron\Models\Job * @return boolean */ public function onClosePending(\Components\Cron\Models\Job $job) { $params = $job->params; $database = App::get('db'); $sconfig = Component::params('com_support'); $slc = "SELECT id, login, email, name FROM `#__support_tickets` AS t"; $upd = "UPDATE `#__support_tickets` AS t SET t.`open`=0, t.`status`=0, t.`closed`=" . $database->quote(Date::toSql()); $where = array(); $where[] = "t.`type`=0"; $where[] = "t.`open`=1"; if (is_object($params)) { $statuses = array(); if (is_numeric($params->get('support_ticketpending_status1'))) { $statuses[] = $params->get('support_ticketpending_status1'); } if (is_numeric($params->get('support_ticketpending_status2'))) { $statuses[] = $params->get('support_ticketpending_status2'); } if (is_numeric($params->get('support_ticketpending_status3'))) { $statuses[] = $params->get('support_ticketpending_status3'); } if (count($statuses)) { $where[] = "t.`status` IN (" . implode(',', $statuses) . ")"; } if ($group = $params->get('support_ticketpending_group')) { $where[] = "t.`group`=" . $database->quote($group); } if ($owners = $params->get('support_ticketpending_owners')) { $usernames = explode(',', $owners); $usernames = array_map('trim', $usernames); foreach ($usernames as $k => $username) { $user = User::getInstance($username); $usernames[$k] = $database->quote($user->get('id')); } $where[] = "t.`owner` IN (" . implode(", ", $usernames) . ")"; } if ($severity = $params->get('support_ticketpending_severity')) { if ($severity != 'all') { $severities = explode(',', $severity); $severities = array_map('trim', $severities); foreach ($severities as $k => $severity) { $severities[$k] = $database->quote($severity); } $where[] = "t.`severity` IN (" . implode(", ", $severities) . ")"; } } if ($owned = intval($params->get('support_ticketpending_owned', 0))) { if ($owned == 1) { $where[] = "(t.`owner` IS NULL OR `owner`='')"; } else { if ($owned == 2) { $where[] = "(t.`owner` IS NOT NULL AND `owner` !='')"; } } } if ($submitters = $params->get('support_ticketpending_submitters')) { $usernames = explode(',', $submitters); $usernames = array_map('trim', $usernames); foreach ($usernames as $k => $username) { $usernames[$k] = $database->quote($username); } $where[] = "t.`login` IN (" . implode(", ", $usernames) . ")"; } if ($tags = $params->get('support_ticketpending_excludeTags', '')) { $tags = explode(',', $tags); $tags = array_map('trim', $tags); foreach ($tags as $k => $tag) { $tags[$k] = $database->quote($tag); } $where[] = "t.`id` NOT IN (\n\t\t\t\t\t\t\tSELECT jto.`objectid` FROM `#__tags_object` AS jto\n\t\t\t\t\t\t\tJOIN `#__tags` AS jt ON jto.`tagid`=jt.`id`\n\t\t\t\t\t\t\tWHERE jto.`tbl`='support'\n\t\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\t\tjt.`tag` IN (" . implode(", ", $tags) . ") OR jt.`raw_tag` IN (" . implode(", ", $tags) . ")\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)"; } if ($tags = $params->get('support_ticketpending_includeTags', '')) { $tags = explode(',', $tags); $tags = array_map('trim', $tags); foreach ($tags as $k => $tag) { $tags[$k] = $database->quote($tag); } $where[] = "t.`id` IN (\n\t\t\t\t\t\t\tSELECT jto.`objectid` FROM `#__tags_object` AS jto\n\t\t\t\t\t\t\tJOIN `#__tags` AS jt ON jto.`tagid`=jt.`id`\n\t\t\t\t\t\t\tWHERE jto.`tbl`='support'\n\t\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\t\tjt.`tag` IN (" . implode(", ", $tags) . ") OR jt.`raw_tag` IN (" . implode(", ", $tags) . ")\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)"; } if ($created = $params->get('support_ticketpending_activity', '-2week')) { $op = ''; switch ($created) { // Created before (older than) case '-day': $op = '<='; $timestamp = Date::modify('-1 day'); break; case '-week': $op = '<='; $timestamp = Date::modify('-1 week'); break; case '-2week': $op = '<='; $timestamp = Date::modify('-2 week'); break; case '-3week': $op = '<='; $timestamp = Date::modify('-3 week'); break; case '-month': $op = '<='; $timestamp = Date::modify('-1 month'); break; case '-6month': $op = '<='; $timestamp = Date::modify('-6 month'); break; case '-year': $op = '<='; $timestamp = Date::modify('-1 year'); break; case '--': $op = ''; break; } if ($op) { $where[] = "(SELECT MAX(c.`created`) FROM `#__support_comments` AS c WHERE c.`ticket`=t.`id`) " . $op . $database->quote($timestamp->toSql()); } } } else { $timestamp = Date::modify('-2 week'); $where[] = "t.`created` <= " . $database->quote($timestamp->toSql()); } if (count($where) > 0) { $slc .= " WHERE " . implode(" AND ", $where); $upd .= " WHERE " . implode(" AND ", $where); } $message_id = $params->get('support_ticketpending_message'); // Get a list of tickets before we update them $tickets = array(); if ($message_id) { $database->setQuery($slc); $tickets = $database->loadObjectList(); } // Update the tickets $database->setQuery($upd); if (!$database->query()) { Log::error('CRON query failed: ' . $database->getErrorMsg()); } else { if ($message_id && !empty($tickets)) { Lang::load('com_support') || Lang::load('com_support', PATH_CORE . DS . 'components' . DS . 'com_support' . DS . 'site'); include_once PATH_CORE . DS . 'components' . DS . 'com_support' . DS . 'tables' . DS . 'message.php'; include_once PATH_CORE . DS . 'components' . DS . 'com_support' . DS . 'models' . DS . 'ticket.php'; $message = new \Components\Support\Tables\Message($database); $message->load($message_id); // Make sure we have a message to send if ($message->message) { $from = array('name' => Config::get('sitename') . ' ' . Lang::txt('COM_SUPPORT'), 'email' => Config::get('mailfrom'), 'multipart' => md5(date('U'))); // Set mail additional args (mail return path - used for bounces) if ($host = Request::getVar('HTTP_HOST', '', 'server')) { $args = '-f hubmail-bounces@' . $host; } $subject = Lang::txt('COM_SUPPORT') . ': ' . Lang::txt('COM_SUPPORT_TICKETS'); $mailed = array(); $message->message = stripslashes($message->message); $message->message = str_replace('{sitename}', Config::get('sitename'), $message->message); $message->message = str_replace('{siteemail}', Config::get('mailfrom'), $message->message); foreach ($tickets as $submitter) { $name = null; $email = null; if ($submitter->login) { // Get the user's account $user = User::getInstance($submitter->login); if (is_object($user) && $user->get('id')) { $name = $user->get('name'); $email = $user->get('email'); } } $email = $email ?: $submitter->email; $name = $name ?: $submitter->name; $name = $name ?: $email; if (!$email) { continue; } // Try to ensure no duplicates /*if (in_array($email, $mailed)) { continue; }*/ $old = new \Components\Support\Models\Ticket($submitter->id); $old->set('open', 1); $row = clone $old; $row->set('open', 0); $comment = new \Components\Support\Models\Comment(); $comment->set('created', Date::toSql()); $comment->set('created_by', 0); $comment->set('access', 0); $comment->set('comment', $message->message); $comment->set('comment', str_replace('#XXX', '#' . $row->get('id'), $comment->get('comment'))); $comment->set('comment', str_replace('{ticket#}', $row->get('id'), $comment->get('comment'))); // Compare fields to find out what has changed for this ticket and build a changelog $comment->changelog()->diff($old, $row); $comment->set('ticket', $row->get('id')); if (!$comment->store()) { $this->setError($comment->getError()); } $eview = new \Hubzero\Mail\View(array('base_path' => PATH_CORE . DS . 'components' . DS . 'com_support' . DS . 'site', 'name' => 'emails', 'layout' => 'comment_plain')); $eview->option = 'com_support'; $eview->controller = 'tickets'; $eview->delimiter = '~!~!~!~!~!~!~!~!~!~!'; $eview->boundary = $from['multipart']; $eview->comment = $comment; $eview->config = $sconfig; $eview->ticket = $row; $plain = $eview->loadTemplate(false); $plain = str_replace("\n", "\r\n", $plain); // HTML $eview->setLayout('comment_html'); $html = $eview->loadTemplate(); $html = str_replace("\n", "\r\n", $html); // Build message $message = new \Hubzero\Mail\Message(); $message->setSubject($subject)->addFrom($from['email'], $from['name'])->addTo($email, $name)->addHeader('X-Component', 'com_support')->addHeader('X-Component-Object', 'support_ticket_comment'); $message->addPart($plain, 'text/plain'); $message->addPart($html, 'text/html'); // Send mail if (!$message->send()) { echo 'CRON email failed: ' . Lang::txt('Failed to mail %s', $email); //$this->setError(Lang::txt('Failed to mail %s', $fullEmailAddress)); Log::error('CRON email failed: ' . Lang::txt('Failed to mail %s', $email)); } $mailed[] = $email; } } } } return true; }
/** * Update a support ticket * * @param integer $toolid Tool ID * @param array $oldstuff Information before any changes * @param array $newstuff Information after changes * @param string $comment Comments to add * @param integer $access Parameter description (if any) ... * @param integer $email Parameter description (if any) ... * @param integer $action Parameter description (if any) ... * @return boolean False if errors, True on success */ protected function _updateTicket($toolid, $oldstuff, $newstuff, $comment, $access = 0, $email = 0, $action = 1, $toolinfo = array()) { $obj = new \Components\Tools\Tables\Tool($this->database); $summary = ''; $rowc = new \Components\Support\Models\Comment(); $rowc->set('ticket', $obj->getTicketId($toolid)); // see what changed if ($oldstuff != $newstuff) { if ($oldstuff['toolname'] != $newstuff['toolname']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_TOOLNAME'), $oldstuff['toolname'], $newstuff['toolname']); } if ($oldstuff['title'] != $newstuff['title']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_TOOL') . ' ' . strtolower(Lang::txt('COM_TOOLS_TITLE')), $oldstuff['title'], $newstuff['title']); $summary .= strtolower(Lang::txt('COM_TOOLS_TITLE')); } if ($oldstuff['version'] != '' && $oldstuff['version'] != $newstuff['version']) { $rowc->changelog()->changed(strtolower(Lang::txt('COM_TOOLS_DEV_VERSION_LABEL')), $oldstuff['version'], $newstuff['version']); $summary .= $summary == '' ? '' : ', '; $summary .= strtolower(Lang::txt('COM_TOOLS_VERSION')); } else { if ($oldstuff['version'] == '' && $newstuff['version'] != '') { $rowc->changelog()->changed(strtolower(Lang::txt('COM_TOOLS_DEV_VERSION_LABEL')), '', $newstuff['version']); } } if ($oldstuff['description'] != $newstuff['description']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_TOOL') . ' ' . strtolower(Lang::txt('COM_TOOLS_DESCRIPTION')), $oldstuff['description'], $newstuff['description']); $summary .= $summary == '' ? '' : ', '; $summary .= strtolower(Lang::txt('COM_TOOLS_DESCRIPTION')); } if ($oldstuff['exec'] != $newstuff['exec']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_TOOL_ACCESS'), $oldstuff['exec'], $newstuff['exec']); if ($newstuff['exec'] == '@GROUP') { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_ALLOWED_GROUPS'), '', \Components\Tools\Helpers\Html::getGroups($newstuff['membergroups'])); } $summary .= $summary == '' ? '' : ', '; $summary .= strtolower(Lang::txt('COM_TOOLS_TOOL_ACCESS')); } if ($oldstuff['code'] != $newstuff['code']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_CODE_ACCESS'), $oldstuff['code'], $newstuff['code']); $summary .= $summary == '' ? '' : ', '; $summary .= strtolower(Lang::txt('COM_TOOLS_CODE_ACCESS')); } if ($oldstuff['wiki'] != $newstuff['wiki']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_WIKI_ACCESS'), $oldstuff['wiki'], $newstuff['wiki']); $summary .= $summary == '' ? '' : ', '; $summary .= strtolower(Lang::txt('COM_TOOLS_WIKI_ACCESS')); } if ($oldstuff['vncGeometry'] != $newstuff['vncGeometry']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_VNC_GEOMETRY'), $oldstuff['vncGeometry'], $newstuff['vncGeometry']); $summary .= $summary == '' ? '' : ', '; $summary .= strtolower(Lang::txt('COM_TOOLS_VNC_GEOMETRY')); } if ($oldstuff['developers'] != $newstuff['developers']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_DEVELOPMENT_TEAM'), \Components\Tools\Helpers\Html::getDevTeam($oldstuff['developers']), \Components\Tools\Helpers\Html::getDevTeam($newstuff['developers'])); $summary .= $summary == '' ? '' : ', '; $summary .= strtolower(Lang::txt('COM_TOOLS_DEVELOPMENT_TEAM')); } // end of tool information changes if ($summary) { $summary .= ' ' . Lang::txt('COM_TOOLS_INFO_CHANGED'); $action = 1; } // tool status/priority changes if ($oldstuff['priority'] != $newstuff['priority']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_PRIORITY'), \Components\Tools\Helpers\Html::getPriority($oldstuff['priority']), \Components\Tools\Helpers\Html::getPriority($newstuff['priority'])); $email = 0; // do not send email about priority changes } if ($oldstuff['state'] != $newstuff['state']) { $rowc->changelog()->changed(Lang::txt('COM_TOOLS_TICKET_CHANGED_FROM'), \Components\Tools\Helpers\Html::getStatusName($oldstuff['state'], $oldstate), \Components\Tools\Helpers\Html::getStatusName($newstuff['state'], $newstate)); $summary = Lang::txt('COM_TOOLS_STATUS') . ' ' . Lang::txt('COM_TOOLS_TICKET_CHANGED_FROM') . ' ' . $oldstate . ' ' . Lang::txt('COM_TOOLS_TO') . ' ' . $newstate; $email = 1; // send email about status changes $action = 2; } } if ($comment) { //$action = $action==2 ? $action : 3; $email = 1; $rowc->set('comment', nl2br($comment)); } $rowc->set('created', Date::toSql()); $rowc->set('created_by', User::get('id')); $rowc->set('access', $access); if (!$rowc->store()) { $this->setError($rowc->getError()); return false; } if ($email) { // send notification emails $summary = $summary ? $summary : $comment; $this->_email($toolid, $summary, $comment, $access, $action, $toolinfo); } return true; }
/** * Delete a ticket comment * * @apiMethod DELETE * @apiUri /support/{ticket}/comments/{comment} * @apiParameter { * "name": "ticket", * "description": "Ticket identifier", * "type": "integer", * "required": true, * "default": 0 * } * @apiParameter { * "name": "comment", * "description": "Comment identifier", * "type": "integer", * "required": true, * "default": 0 * } * @return void */ public function deleteTask() { $this->requiresAuthentication(); if (!$this->acl->check('delete', 'comments')) { throw new Exception(Lang::txt('Not authorized'), 403); } $ticket_id = Request::getInt('ticket', 0); $comment_id = Request::getInt('comment', 0); $ticket = new \Components\Support\Models\Ticket($ticket_id); if (!$ticket->exists()) { throw new Exception(Lang::txt('COM_SUPPORT_ERROR_MISSING_RECORD'), 404); } $comment = new \Components\Support\Models\Comment($comment_id); if (!$comment->exists()) { throw new Exception(Lang::txt('COM_SUPPORT_ERROR_MISSING_RECORD'), 404); } if ($comment->isPrivate() && !$this->acl->check('delete', 'private_comments')) { throw new Exception(Lang::txt('COM_SUPPORT_ERROR_UNAUTHORIZED'), 403); } if (!$comment->delete()) { throw new Exception($comment->getError(), 500); } $this->send(null, 204); }