/** * Fetch the element * * @param string $name Element name * @param string $value Element value * @param object &$node XMLElement node object containing the settings for the element * @param string $control_name Control name * @return string * @since 1.3.1 */ public function fetchElement($name, $value, &$node, $control_name) { $db = \App::get('db'); $html = array(); $html[] = '<select name="' . $control_name . '[' . $name . ']" id="' . $control_name . $name . '">'; include_once PATH_CORE . DS . 'components' . DS . 'com_support' . DS . 'tables' . DS . 'status.php'; $sr = new \Components\Support\Tables\Status($db); $status = $sr->find('list', array('sort' => 'open', 'sort_Dir' => 'DESC')); $html[] = '<option value=""' . ($value === '' || $value === null ? ' selected="selected"' : '') . '>--</option>'; $html[] = '<option value="0"' . ($value === 0 || $value === '0' ? ' selected="selected"' : '') . '>open: New</option>'; $switched = false; foreach ($status as $anode) { if (!$anode->open && !$switched) { $html[] = '<option value="-1"' . ($value == -1 ? ' selected="selected"' : '') . '>closed: No resolution</option>'; $switched = true; } $html[] = '<option value="' . $anode->id . '"' . ($value == $anode->id ? ' selected="selected"' : '') . '>' . ($anode->open ? 'open: ' : 'closed: ') . stripslashes($anode->title) . '</option>'; } $html[] = '</select>'; return implode("\n", $html); }
/** * Display a list of tickets * * @apiMethod GET * @apiUri /support/list * @apiParameter { * "name": "limit", * "description": "Number of result to return.", * "type": "integer", * "required": false, * "default": 25 * } * @apiParameter { * "name": "limitstart", * "description": "Number of where to start returning results.", * "type": "integer", * "required": false, * "default": 0 * } * @apiParameter { * "name": "search", * "description": "A word or phrase to search for.", * "type": "string", * "required": false, * "default": "" * } * @apiParameter { * "name": "sort", * "description": "Field to sort results by.", * "type": "string", * "required": false, * "default": "created", * "allowedValues": "created, id, state" * } * @apiParameter { * "name": "sort_Dir", * "description": "Direction to sort results by.", * "type": "string", * "required": false, * "default": "desc", * "allowedValues": "asc, desc" * } * @return void */ public function listTask() { $this->requiresAuthentication(); if (!$this->acl->check('read', 'tickets')) { throw new Exception(Lang::txt('Not authorized'), 403); } $obj = new \Components\Support\Tables\Ticket($this->database); $filters = array('limit' => Request::getInt('limit', 25), 'start' => Request::getInt('limitstart', 0), 'search' => Request::getVar('search', ''), 'sort' => Request::getWord('sort', 'created'), 'sortdir' => strtoupper(Request::getWord('sort_Dir', 'DESC')), 'group' => Request::getVar('group', ''), 'reportedby' => Request::getVar('reporter', ''), 'owner' => Request::getVar('owner', ''), 'type' => Request::getInt('type', 0), 'status' => strtolower(Request::getWord('status', '')), 'tag' => Request::getWord('tag', '')); $filters['opened'] = $this->_toTimestamp(Request::getVar('opened', '')); $filters['closed'] = $this->_toTimestamp(Request::getVar('closed', '')); $response = new stdClass(); $response->success = true; $response->total = 0; $response->tickets = array(); // Get a list of all statuses $sobj = new \Components\Support\Tables\Status($this->database); $statuses = array(); if ($data = $sobj->find('all')) { foreach ($data as $status) { $statuses[$status->id] = $status; } } // Get a count of tickets $response->total = $obj->getTicketsCount($filters); if ($response->total) { $response->tickets = $obj->getTickets($filters); foreach ($response->tickets as $i => $ticket) { $owner = $ticket->owner; $response->tickets[$i]->owner = new stdClass(); $response->tickets[$i]->owner->username = $ticket->username; $response->tickets[$i]->owner->name = $ticket->owner_name; $response->tickets[$i]->owner->id = $ticket->owner_id; unset($response->tickets[$i]->owner_name); unset($response->tickets[$i]->owner_id); unset($response->tickets[$i]->username); $response->tickets[$i]->reporter = new stdClass(); $response->tickets[$i]->reporter->name = $ticket->name; $response->tickets[$i]->reporter->username = $ticket->login; $response->tickets[$i]->reporter->email = $ticket->email; unset($response->tickets[$i]->name); unset($response->tickets[$i]->login); unset($response->tickets[$i]->email); $status = $response->tickets[$i]->status; $response->tickets[$i]->status = new stdClass(); if (!$status) { $response->tickets[$i]->status->alias = 'new'; $response->tickets[$i]->status->title = 'New'; } else { $response->tickets[$i]->status->alias = isset($statuses[$status]) ? $statuses[$status]->alias : 'unknown'; $response->tickets[$i]->status->title = isset($statuses[$status]) ? $statuses[$status]->title : 'unknown'; } $response->tickets[$i]->status->id = $status; $response->tickets[$i]->url = str_replace('/api', '', rtrim(Request::base(), '/') . '/' . ltrim(Route::url('index.php?option=com_support&controller=tickets&task=tickets&id=' . $response->tickets[$i]->id), '/')); } } $this->send($response); }
/** * Close tickets in a specified state * * @return boolean */ public function onAfterRepositoryUpdate() { $database = App::get('db'); $sconfig = Component::params('com_support'); $open = 0; $status = $this->params->get('support_ticket_closed', 0); $status = $status == '-1' ? 0 : $status; if ($status) { include_once PATH_CORE . DS . 'components' . DS . 'com_support' . DS . 'tables' . DS . 'status.php'; $st = new \Components\Support\Tables\Status($database); $st->load($status); $open = $st->open; } $slc = "SELECT id, login, email, name FROM `#__support_tickets` AS t"; $upd = "UPDATE `#__support_tickets` AS t SET t.`open`=" . $database->quote($open) . ", t.`status`=" . $database->quote($status) . ", t.`closed`=" . $database->quote(Date::toSql()); $where = array(); $where[] = "t.`type`=0"; $where[] = "t.`open`=1"; // Gather a list of statuses $statuses = array(); if (is_numeric($this->params->get('support_ticket_state1'))) { $statuses[] = $this->params->get('support_ticket_state1'); } if (is_numeric($this->params->get('support_ticket_state2'))) { $statuses[] = $this->params->get('support_ticket_state2'); } if (is_numeric($this->params->get('support_ticket_state3'))) { $statuses[] = $this->params->get('support_ticket_state3'); } if (count($statuses)) { $where[] = "t.`status` IN (" . implode(',', $statuses) . ")"; } // Only tickets for a specified group? if ($group = $this->params->get('support_ticket_group')) { $where[] = "t.`group`=" . $database->quote($group); } // Only tickets for specified owners? if ($owners = $this->params->get('support_ticket_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) . ")"; } // Tickets with a specified severity? if ($severity = $this->params->get('support_ticket_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) . ")"; } } // Only tickets by specified submitters if ($submitters = $this->params->get('support_ticket_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) . ")"; } // Tickets WITHOUT specified tags if ($tags = $this->params->get('support_ticket_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\tSELECT jto.`objectid` FROM `#__tags_object` AS jto\n\t\t\t\t\t\tJOIN `#__tags` AS jt ON jto.`tagid`=jt.`id`\n\t\t\t\t\t\tWHERE jto.`tbl`='support'\n\t\t\t\t\t\tAND (\n\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)\n\t\t\t\t\t)"; } // Tickets WITH specified tags if ($tags = $this->params->get('support_ticket_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\tSELECT jto.`objectid` FROM `#__tags_object` AS jto\n\t\t\t\t\t\tJOIN `#__tags` AS jt ON jto.`tagid`=jt.`id`\n\t\t\t\t\t\tWHERE jto.`tbl`='support'\n\t\t\t\t\t\tAND (\n\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)\n\t\t\t\t\t)"; } // Last activity within specified time range if ($created = $this->params->get('support_ticket_activity')) { $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()); } } if (count($where) > 0) { $slc .= " WHERE " . implode(" AND ", $where); $upd .= " WHERE " . implode(" AND ", $where); } $message_id = $this->params->get('support_ticket_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('Ticket query failed: ' . $database->getErrorMsg()); return false; } // If we're sending a message... 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 = str_replace('{sitename}', Config::get('sitename'), $message->message); $message->message = str_replace('{siteemail}', Config::get('mailfrom'), $message->message); $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); 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->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')); $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()) { Log::error('Ticket email failed: ' . Lang::txt('Failed to mail %s', $email)); } $mailed[] = $email; } } } return true; }
<tr class="odd"> <th scope="row"><?php echo Lang::txt('COM_SUPPORT_STATS_NO_RESOLUTION'); ?> </th> <td><?php echo isset($res[0]) ? $res[0] : '0'; ?> </td> <td><?php echo isset($res[0]) ? $res[0] / $total : '0'; ?> </td> </tr> <?php $sr = new \Components\Support\Tables\Status($database); $resolutions = $sr->find('list', array('open' => 0)); $cls = 'odd'; $data = array("{label: '" . Lang::txt('COM_SUPPORT_STATS_NO_RESOLUTION') . "', data: " . (isset($res[0]) ? $res[0] / $total : '0') . ", color: '" . $colors[0] . "'}"); $i = 1; foreach ($resolutions as $resolution) { $r = "{label: '" . $this->escape(addslashes($resolution->title)) . "', data: "; $r .= isset($res[$resolution->id]) ? round($res[$resolution->id] / $total * 100, 2) : 0; $r .= ", color: '" . $colors[$i] . "'}"; $data[] = $r; $cls = $cls == 'even' ? 'odd' : 'even'; ?> <tr class="<?php echo $cls; ?> ">
/** * Create a new record * * @return object */ public function getConditions() { $conditions = new stdClass(); $conditions->owner = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false), $this->_operator('LIKE \'%$1%\'', 'contains', false), $this->_operator('LIKE \'$1%\'', 'starts with', false), $this->_operator('LIKE \'%$1\'', 'ends with', false), $this->_operator('NOT LIKE \'%$1%\'', 'does not contain', false), $this->_operator('NOT LIKE \'$1%\'', 'does not start with', false), $this->_operator('NOT LIKE \'%$1\'', 'does not end with', false)), 'text'); // Groups $items = array($this->_value('*', Lang::txt('(any of mine)'), true)); if ($xgroups = \Hubzero\User\Helper::getGroups(User::get('id'), 'members')) { foreach ($xgroups as $xgroup) { $xgroup->description = trim($xgroup->description) ?: $xgroup->cn; $items[] = $this->_value($xgroup->cn, stripslashes($this->escape($xgroup->description)), false); } } $conditions->group = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false), $this->_operator('LIKE \'%$1%\'', 'contains', false), $this->_operator('LIKE \'$1%\'', 'starts with', false), $this->_operator('LIKE \'%$1\'', 'ends with', false), $this->_operator('NOT LIKE \'%$1%\'', 'does not contain', false), $this->_operator('NOT LIKE \'$1%\'', 'does not start with', false), $this->_operator('NOT LIKE \'%$1\'', 'does not end with', false)), $items); $conditions->login = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false), $this->_operator('LIKE \'%$1%\'', 'contains', false), $this->_operator('LIKE \'$1%\'', 'starts with', false), $this->_operator('LIKE \'%$1\'', 'ends with', false), $this->_operator('NOT LIKE \'%$1%\'', 'does not contain', false), $this->_operator('NOT LIKE \'$1%\'', 'does not start with', false), $this->_operator('NOT LIKE \'%$1\'', 'does not end with', false)), 'text'); $conditions->id = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false), $this->_operator('lt', 'less than', false), $this->_operator('gt', 'grater than', false), $this->_operator('=lt', 'less than or equal to', false), $this->_operator('gt=', 'greater than or equal to', false)), 'text'); $conditions->report = $this->_expression(array($this->_operator('=', 'is', false), $this->_operator('!=', 'is not', false), $this->_operator('LIKE \'%$1%\'', 'contains', true), $this->_operator('LIKE \'$1%\'', 'starts with', false), $this->_operator('LIKE \'%$1\'', 'ends with', false), $this->_operator('NOT LIKE \'%$1%\'', 'does not contain', false), $this->_operator('NOT LIKE \'$1%\'', 'does not start with', false), $this->_operator('NOT LIKE \'%$1\'', 'does not end with', false)), 'text'); $conditions->open = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false)), array($this->_value('1', 'open', true), $this->_value('0', 'closed', false))); $sr = new \Components\Support\Tables\Status($this->database); $status = $sr->find('list', array('sort' => 'open', 'sort_Dir' => 'DESC')); $items = array(); $items[] = $this->_value(0, $this->escape('open: New'), true); if (isset($status) && is_array($status)) { $switched = false; foreach ($status as $anode) { if (!$anode->open && !$switched) { $items[] = $this->_value(-1, $this->escape('closed: No resolution'), false); $switched = true; } $items[] = $this->_value($anode->id, $this->escape(($anode->open ? 'open: ' : 'closed: ') . stripslashes($anode->title)), false); } } $conditions->status = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false)), $items); $conditions->created = $this->_expression(array($this->_operator('=', 'on', true), $this->_operator('lt', 'before', false), $this->_operator('gt', 'after', false)), 'text'); $conditions->closed = $this->_expression(array($this->_operator('=', 'on', true), $this->_operator('lt', 'before', false), $this->_operator('gt', 'after', false)), 'text'); $conditions->tag = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false)), 'text'); $conditions->type = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false)), array($this->_value('0', 'user submitted', true), $this->_value('1', 'automatic', false), $this->_value('3', 'tool', false))); $severities = Utilities::getSeverities($this->config->get('severities')); $items = 'text'; if (isset($severities) && is_array($severities)) { $items = array(); foreach ($severities as $severity) { $sel = false; if ($severity == 'normal') { $sel = true; } $items[] = $this->_value($severity, $severity, $sel); } } $conditions->severity = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false)), $items); $sc = new Category($this->database); $categories = $sc->find('list'); $items = 'text'; if (isset($categories) && is_array($categories)) { $items = array(); foreach ($categories as $anode) { $sel = false; $items[] = $this->_value($this->escape($anode->alias), $this->escape(stripslashes($anode->title)), $sel); } } $conditions->category = $this->_expression(array($this->_operator('=', 'is', true), $this->_operator('!=', 'is not', false)), $items); return $conditions; }