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 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 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->lastInserId(); // 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 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 check_access($f3){ if(!$f3->exists('SESSION.user')){ // $f3->set('SESSION.error', 'You don\'t have permission for this ticket.'); $f3->reroute('/login'); } } 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); } }