Ticket Templates. The work is in * functions/ticket_template.php. */ defined('FROM_POST_HANDLER') || die("Direct file access is not allowed"); /** The template a request names - back to the list with an error when it is gone. */ function ticketTemplateForRequest($ticket_template_id) { $row = ticketTemplateRow($ticket_template_id); if (!$row) { flashAlert('That ticket template no longer exists.', 'error'); redirect('ticket_templates.php'); } return $row; } if (isset($_POST['add_ticket_template']) || isset($_POST['edit_ticket_template'])) { validateCSRFToken(); $editing = isset($_POST['edit_ticket_template']); $ticket_template_id = 0; if ($editing) { $ticket_template_id = intval(ticketTemplateForRequest($_POST['ticket_template_id'] ?? 0)['ticket_template_id']); } $fields = ticketTemplateFields($_POST, $error); if (!$fields) { flashAlert($error, 'error'); redirect(); } $ticket_template_id = ticketTemplateSave($ticket_template_id, $fields); $name = escapeSql($fields['name']); // A new one can go at the end of a project template's tickets $project_template_id = intval($_POST['project_template'] ?? 0); if (!$editing && $project_template_id && mysqli_num_rows(mysqli_query($mysqli, "SELECT 1 FROM project_templates WHERE project_template_id = $project_template_id"))) { $order = intval(mysqli_fetch_row(mysqli_query($mysqli, "SELECT COALESCE(MAX(ticket_template_order), 0) + 1 FROM project_template_ticket_templates WHERE project_template_id = $project_template_id"))[0]); mysqli_query($mysqli, "INSERT INTO project_template_ticket_templates SET project_template_id = $project_template_id, ticket_template_id = $ticket_template_id, ticket_template_order = $order"); } logAudit("Ticket Template", $editing ? "Edit" : "Create", "$session_name " . ($editing ? 'edited' : 'created') . " ticket template $name", 0, $ticket_template_id); flashAlert("Ticket template " . escapeHtml($fields['name']) . " " . ($editing ? 'saved' : 'created')); // A new one opens, to add its tasks redirect($editing ? null : "ticket_template.php?ticket_template_id=$ticket_template_id"); } if (isset($_GET['copy_ticket_template'])) { validateCSRFToken(); $row = ticketTemplateForRequest($_GET['copy_ticket_template']); $new_id = ticketTemplateCopy($row['ticket_template_id']); logAudit("Ticket Template", "Create", "$session_name copied ticket template " . escapeSql($row['ticket_template_name']), 0, $new_id); flashAlert("Ticket template " . escapeHtml($row['ticket_template_name']) . " copied - this is the copy"); redirect("ticket_template.php?ticket_template_id=$new_id"); } if (isset($_GET['archive_ticket_template']) || isset($_GET['restore_ticket_template'])) { validateCSRFToken(); $archive = isset($_GET['archive_ticket_template']); $row = ticketTemplateForRequest($archive ? $_GET['archive_ticket_template'] : $_GET['restore_ticket_template']); $ticket_template_id = intval($row['ticket_template_id']); $name = escapeSql($row['ticket_template_name']); // Archived, it isn't offered for new tickets - recurring tickets and project templates that use it keep it, so restoring it is all it takes mysqli_query($mysqli, "UPDATE ticket_templates SET ticket_template_archived_at = " . ($archive ? 'NOW()' : 'NULL') . " WHERE ticket_template_id = $ticket_template_id"); logAudit("Ticket Template", $archive ? "Archive" : "Restore", "$session_name " . ($archive ? 'archived' : 'restored') . " ticket template $name", 0, $ticket_template_id); flashAlert("Ticket template " . escapeHtml($row['ticket_template_name']) . " " . ($archive ? 'archived' : 'restored'), $archive ? 'error' : 'success'); redirect(); } if (isset($_GET['delete_ticket_template'])) { validateCSRFToken(); $row = ticketTemplateForRequest($_GET['delete_ticket_template']); $ticket_template_id = intval($row['ticket_template_id']); $ticket_template_name = escapeSql($row['ticket_template_name']); mysqli_query($mysqli, "DELETE FROM ticket_templates WHERE ticket_template_id = $ticket_template_id"); // Its tasks and tags go with it, and it comes off the project templates that raise it mysqli_query($mysqli, "DELETE FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id"); mysqli_query($mysqli, "DELETE FROM ticket_template_tags WHERE ticket_template_id = $ticket_template_id"); mysqli_query($mysqli, "DELETE FROM project_template_ticket_templates WHERE ticket_template_id = $ticket_template_id"); // Unlink from recurring tickets rather than deleting them - the schedule is still // wanted, it just stops contributing tasks to the tickets it raises. Tickets raised // from it keep everything they were given, but not the link. mysqli_query($mysqli, "UPDATE recurring_tickets SET recurring_ticket_ticket_template_id = 0 WHERE recurring_ticket_ticket_template_id = $ticket_template_id"); mysqli_query($mysqli, "UPDATE tickets SET ticket_template_id = 0 WHERE ticket_template_id = $ticket_template_id"); logAudit("Ticket Template", "Delete", "$session_name deleted ticket template $ticket_template_name"); flashAlert("Ticket template " . escapeHtml($row['ticket_template_name']) . " and its tasks deleted", 'error'); redirect(isset($_GET['from_page']) ? 'ticket_templates.php' : null); } if (isset($_POST['add_ticket_template_task'])) { validateCSRFToken(); $row = ticketTemplateForRequest($_POST['ticket_template_id'] ?? 0); $ticket_template_id = intval($row['ticket_template_id']); $task_name = trim(mb_substr(strip_tags((string) ($_POST['task_name'] ?? '')), 0, 200)); if ($task_name === '') { flashAlert('Give the task a name.', 'error'); redirect(); } $estimate = max(0, min(100000, intval($_POST['task_estimate'] ?? 0))); $task_name_sql = escapeSql($task_name); $order = intval(mysqli_fetch_row(mysqli_query($mysqli, "SELECT COALESCE(MAX(task_template_order), 0) + 1 FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id"))[0]); mysqli_query($mysqli, "INSERT INTO task_templates SET task_template_name = '$task_name_sql', task_template_order = $order, task_template_completion_estimate = $estimate, task_template_ticket_template_id = $ticket_template_id"); logAudit("Ticket Template", "Edit", "$session_name added task $task_name_sql to ticket template " . escapeSql($row['ticket_template_name']), 0, $ticket_template_id); flashAlert("Task " . escapeHtml($task_name) . " added"); redirect(); } if (isset($_POST['edit_ticket_template_task'])) { validateCSRFToken(); $task_template_id = intval($_POST['task_template_id'] ?? 0); $task = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT task_template_ticket_template_id FROM task_templates WHERE task_template_id = $task_template_id")); $row = ticketTemplateForRequest($task['task_template_ticket_template_id'] ?? 0); $task_name = trim(mb_substr(strip_tags((string) ($_POST['name'] ?? '')), 0, 200)); if ($task_name === '') { flashAlert('Give the task a name.', 'error'); redirect(); } $task_name_sql = escapeSql($task_name); $estimate = max(0, min(100000, intval($_POST['completion_estimate'] ?? 0))); // Its place in the list stays as it is - the list is reordered by dragging mysqli_query($mysqli, "UPDATE task_templates SET task_template_name = '$task_name_sql', task_template_completion_estimate = $estimate WHERE task_template_id = $task_template_id"); logAudit("Ticket Template", "Edit", "$session_name edited task $task_name_sql on ticket template " . escapeSql($row['ticket_template_name']), 0, intval($row['ticket_template_id'])); flashAlert("Task " . escapeHtml($task_name) . " saved"); redirect(); } if (isset($_GET['delete_task_template'])) { validateCSRFToken(); $task_template_id = intval($_GET['delete_task_template']); $task = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT task_template_name, task_template_ticket_template_id FROM task_templates WHERE task_template_id = $task_template_id")); $row = ticketTemplateForRequest($task['task_template_ticket_template_id'] ?? 0); mysqli_query($mysqli, "DELETE FROM task_templates WHERE task_template_id = $task_template_id"); logAudit("Ticket Template", "Edit", "$session_name deleted task " . escapeSql($task['task_template_name']) . " from ticket template " . escapeSql($row['ticket_template_name']), 0, intval($row['ticket_template_id'])); flashAlert("Task " . escapeHtml($task['task_template_name']) . " deleted", 'error'); redirect(); }