tp_servicedesk/app/controllers/TicketController.php
2025-02-23 09:49:52 +00:00

301 lines
9.6 KiB
PHP

<?php
class TicketController implements CRUD {
use RequiresAuth;
// list all tickts
public function index($f3){
$this->check_access($f3);
$db = $f3->get('DB');
// retrieve tickets
$tickets = $db->exec('SELECT * FROM tickets ORDER BY created_at DESC');
// pass data to template
$f3->set('tickets', $tickets);
// render
$f3->set('content', '../ui/views/ticket/index.html');
echo \Template::instance()->render('../ui/templates/layout.html');
$f3->clear('SESSION.error');
}
// view a single ticket
// TODO_PROJECTS: show a link back to the related project
public function view($f3){
$this->check_access($f3);
$ticket_id = $f3->get('PARAMS.id');
$db = $f3->get('DB');
$this->get_ticket($f3, $db, $ticket_id);
$this->get_child_tickets($f3, $db, $ticket_id);
$this->get_parent_tickets($f3, $db, $ticket_id);
$this->get_custom_fields($f3, $db, $ticket_id);
// render
$f3->set('js', 'ticket_view.js');
$f3->set('content', '../ui/views/ticket/view.html');
echo \Template::instance()->render('../ui/templates/layout.html');
}
// show create form
// TODO_PROJECTS: dropdown to associate ticket with project
public function createForm($f3){
$this->check_access($f3);
$f3->set('content', '../ui/views/ticket/create.html');
echo \Template::instance()->render('../ui/templates/layout.html');
}
// handle POST
// including custom forms
public function create($f3){
$this->check_access($f3);
$title = $f3->get('POST.title');
$description = $f3->get('POST.description');
$priority = $f3->get('POST.priority'); // eg - low, medium, high
$status = $f3->get('POST.status'); // eg - new, in_progress
$created_by = $f3->get('SESSION.user.id'); // current logged in user
$db = $f3->get('DB');
$db->exec(
'INSERT
INTO tickets (title, description, priority, status, created_by, created_at, updated_at)
VALUES (?,?,?,?,?,NOW(), NOW())',
[$title, $description, $priority, $status, $created_by]
);
$ticket_id = $db->lastInsertId();
// custom fields
$meta_keys = $f3->get('POST.meta_key'); // eg ['department', 'category']
$meta_values = $f3->get('POST.meta_value');
if(is_array($meta_keys) && is_array($meta_values)){
foreach($meta_keys as $index => $key){
$val = $meta_values[$index] ?? '';
if(!empty($key) && $val !== ''){
$db->exec(
'INSERT INTO ticket_meta (ticket_id, meta_key, meta_value)
VALUES (?,?,?)',
[$ticket_id, $key, $val]
);
}
}
}
// reroute to ticket
$f3->reroute('/ticket/'.$ticket_id);
}
// show edit form
// including custom forms
// TODO_PROJECTS: allow reasssigning or removing a project association
public function editForm($f3){
$this->check_access($f3);
$ticket_id = $f3->get('PARAMS.id');
$db = $f3->get('DB');
$ticket = $this->get_ticket_check_edit_permission($f3);
$f3->set('ticket', $ticket);
// fetch custom fields
$meta = $db->exec(
'SELECT id, meta_key, meta_value
FROM ticket_meta
WHERE ticket_id = ?',
[$ticket_id]
);
$f3->set('ticket_meta', $meta);
$f3->set('ticket', $ticket);
$f3->set('content', '../ui/views/ticket/edit.html');
echo \Template::instance()->render('../ui/templates/layout.html');
}
// process edit POST TODO: if assigned or admin
public function update($f3){
$this->check_access($f3);
$ticket = $this->get_ticket_check_edit_permission($f3);
$ticket_id = $ticket['id'];
$db = $f3->get('DB');
// get updated fields from post
$title = $f3->get('POST.title');
$description = $f3->get('POST.description');
$priority = $f3->get('POST.priority'); // eg - low, medium, high
$status = $f3->get('POST.status'); // eg - new, in_progress
$updated_by = $f3->get('SESSION.user.id'); // current logged in user
// TODO: if you want to update assignment, should be added here.
$db->exec(
'UPDATE tickets
SET title=?, description=?, priority=?, status=?, updated_by=?, updated_at=?
WHERE id=?',
[$title, $description, $priority, $status, $updated_by, 'NOW()', $ticket_id]
);
// handle custom fields
// 1. update existing custom fields
$meta_ids = $f3->get('POST.meta_id');
$meta_keys = $f3->get('POST.meta_key');
$meta_values = $f3->get('POST.meta_value');
if(is_array($meta_ids) && is_array($meta_keys) && is_array($meta_values)){
foreach($meta_ids as $idx => $m_id){
$m_key = $meta_keys[$idx] ?? '';
$m_val = $meta_values[$idx] ?? '';
if(!empty($m_key) && $m_val !== ''){
$db->exec(
'UPDATE ticket_meta
SET meta_key = ?, meta_value=?
WHERE id = ? AND ticket_id = ?',
[$m_key, $m_val, $m_id, $ticket_id]
);
} else {
// delete if the user cleared it
$db->exec(
'DELETE FROM ticket_meta
WHERE id =? AND ticket_id = ?',
[$m_id, $ticket_id]
);
}
}
}
// 2. insert new fields
$new_keys = $f3->get('POST.new_meta_key');
$new_values = $f3->get('POST.new_meta_value');
if(is_array($new_keys) && is_array($new_values)){
foreach($new_keys as $idx => $n_key){
$n_val = $new_values[$idx] ?? '';
if(!empty($n_key) && $n_val !== ''){
$db->exec(
'INSERT INTO ticket_meta (ticket_id, meta_key, meta_value)
VALUES (?,?,?)',
[$ticket_id, $n_key, $n_val]
);
}
}
}
$f3->reroute('/ticket/' . $ticket_id);
}
// subtask
public function addSubtask($f3){
$this->check_access($f3);
$parent_id = (int) $f3->get('PARAMS.id');
$child_id = (int) $f3->get('POST.child_ticket_id');
$db = $f3->get('DB');
// TODO check that both parent and child tickets exist
// ensure you don't link a ticket to itself, etc.
// insert or ignore
$db->exec(
'INSERT IGNORE INTO ticket_relations (parent_ticket_id, child_ticket_id)
VALUES (?, ?)',
[$parent_id, $child_id]
);
$f3->reroute('/ticket/' . $parent_id);
}
protected function get_ticket_check_edit_permission($f3){
$db = $f3->get('DB');
$ticket_id = $f3->get('PARAMS.id');
$result = $db->exec('SELECT * FROM tickets WHERE id = ? LIMIT 1', [$ticket_id]);
if(!$result){
$f3->set('SESSION.error', 'Ticket not found.');
$f3->reroute('/tickets');
}
$ticket = $result[0];
// TODO: refine
$current_user = $f3->get('SESSION.user');
$is_admin = (isset($current_user['role_name']) && $current_user['role_name'] == 'admin');
$is_assigned = ($ticket['assigned_to'] == $current_user['id']);
if(!$is_admin && !$is_assigned){ // should this be ||
// if not assigned and not admin, disallow edit
$f3->set('SESSION.error', 'You do not have permission to edit this ticket.');
$f3->reroute('/tickets');
}
return $ticket;
}
protected function get_ticket($f3, $db, $ticket_id){
$result = $db->exec(
'SELECT t.*, u.username as created_by_name
FROM tickets t
LEFT JOIN users u ON t.created_by = u.id
WHERE t.id =? LIMIT 1',
[$ticket_id]
);
if(!$result){
// no record
$f3->set('SESSION.error', 'Ticket not found.');
$f3->reroute('/tickets');
}
$ticket = $result[0];
$f3->set('ticket', $ticket);
}
protected function get_child_tickets($f3, $db, $ticket_id){
$child_tickets = $db->exec(
'SELECT c.*
FROM ticket_relations r
INNER JOIN tickets c ON r.child_ticket_id = c.id
WHERE r.parent_ticket_id = ?',
[$ticket_id]);
$f3->set('child_tickets', $child_tickets);
}
protected function get_parent_tickets($f3, $db, $ticket_id){
$parent_tickets = $db->exec(
'SELECT p.*
FROM ticket_relations r
INNER JOIN tickets p ON r.parent_ticket_id = p.id
WHERE r.child_ticket_id = ?',
[$ticket_id]
);
$f3->set('parent_tickets', $parent_tickets);
}
protected function get_custom_fields($f3, $db, $ticket_id){
$meta = $db->exec(
'SELECT meta_key, meta_value
FROM ticket_meta
WHERE ticket_id = ?',
[$ticket_id]
);
// convert meta rows into assoc array
$meta_array = [];
foreach($meta as $m){
$meta_array[$m['meta_key']] = $m['meta_value'];
}
$f3->set('ticket_meta', $meta_array);
}
}