Files
itflow/api/v1/documents/update.php
johnnyq ea23a2bad5 Audit logs stage 1: Admin > Audit Logs rebuilt on the standard list with search, sortable columns and paging, filters for date, who (agent, portal contact or ITFlow itself), client, type and action, and counted views for Changes, Deletions, Sign-ins, Security and Data out; each entry shows who with their avatar, the client, the type and action as a coloured label, the description without the name in front, the IP and device in words, and links to its record while it exists or says No longer here; a quick look with the full entry, the raw user agent, everything from that IP, the record's other entries and what the same person did 15 minutes either side; CSV/PDF export with the page's filters, view and picked columns, itself audited; new functions/audit_log.php, admin/modals/audit_log/audit_log.php and audit_log_export.php, admin/post/audit_log.php and audit_logs export columns; agent/files.php takes ?open= for a file's quick look; database 3.3.1 adds log_client_id and log_entity_id keys on logs, gives each action one name (Unarchive/Restored to Restore, Deleted, Merged, Closed, Reopened, Resolved and Sent to Delete, Merge, Close, Reopen, Resolve and Send, Client Access to Denied, saved card and payment provider Updates to Create or Delete, contract template Update to Edit, type client to Client) and repoints entries at the right record (reply edits and redactions to the ticket, API document edits to the document, reimbursements to the recording expense, API client restores to the client), guarded so it can run again; logAudit call sites in agent, admin, api, client, cron and functions use the same names and record ids
2026-10-18 22:36:25 -04:00

134 lines
5.3 KiB
PHP

<?php
require_once '../validate_api_key.php';
require_once '../require_post_method.php';
// Parse ID
$document_id = intval($_POST['document_id'] ?? 0);
// Default
$update_count = false;
if (!empty($document_id)) {
// 1) Load the current document (scoped to this client)
$sql_original_document = mysqli_query(
$mysqli,
"SELECT document_content, document_created_at, document_created_by, document_description,
document_name, document_updated_at, document_updated_by FROM documents
WHERE document_client_id = $client_id
AND document_id = $document_id
LIMIT 1"
);
if ($sql_original_document && mysqli_num_rows($sql_original_document) === 1) {
$row = mysqli_fetch_assoc($sql_original_document);
// Pull original fields for versioning
$original_document_name = escapeSql($row['document_name']);
$original_document_description = escapeSql($row['document_description']);
$original_document_content = mysqli_real_escape_string($mysqli, $row['document_content']);
$original_document_created_by = intval($row['document_created_by']);
$original_document_updated_by = intval($row['document_updated_by']);
$original_document_created_at = escapeSql($row['document_created_at']);
$original_document_updated_at = escapeSql($row['document_updated_at']);
// Determine who/when created the version (same logic as app)
if (!empty($original_document_updated_at)) {
$document_version_created_at = $original_document_updated_at;
} else {
$document_version_created_at = $original_document_created_at;
}
if (!empty($original_document_updated_by)) {
$document_version_created_by = $original_document_updated_by;
} else {
$document_version_created_by = $original_document_created_by;
}
// 2) Save the current version into document_versions
mysqli_query(
$mysqli,
"INSERT INTO document_versions SET
document_version_name = '$original_document_name',
document_version_description = '$original_document_description',
document_version_content = '$original_document_content',
document_version_created_by = $document_version_created_by,
document_version_created_at = '$document_version_created_at',
document_version_document_id = $document_id"
);
$document_version_id = mysqli_insert_id($mysqli);
// 3) Variable assignment from POST
// This should set: $name, $description, $content (raw html), $folder, etc.
// Fetch current doc data (fresh)
$document_row = mysqli_fetch_assoc(mysqli_query($mysqli, "
SELECT * FROM documents
WHERE document_client_id = $client_id
AND document_id = $document_id
LIMIT 1
"));
// Assign variables from POST or fallback to DB
require_once 'document_model.php';
// Process NEW HTML content: save base64 images to /uploads/documents/<document_id>/
// In-app uses $_POST['content'] as raw; in API you likely map to $content in document_model.php
$raw_post_content = $content;
$processed_html = saveBase64Images(
$raw_post_content,
$_SERVER['DOCUMENT_ROOT'] . "/uploads/documents/",
"uploads/documents/",
$document_id
);
// Escape for DB
$content_db = mysqli_real_escape_string($mysqli, $processed_html);
// Rebuild content_raw for full-text search (same technique as app)
$content_raw = escapeSql($name . " " . str_replace("<", " <", $processed_html));
$content_raw = mysqli_real_escape_string($mysqli, $content_raw);
// Escape name/description too (document_model.php may already sanitize; do DB escaping here regardless)
$name_db = mysqli_real_escape_string($mysqli, $name);
$description_db = mysqli_real_escape_string($mysqli, $description);
$folder_id = intval($folder);
// 4) Update the document (IMPORTANT: proper WHERE + scope to client)
mysqli_query(
$mysqli,
"UPDATE documents SET
document_name = '$name_db',
document_description = '$description_db',
document_content = '$content_db',
document_content_raw = '$content_raw',
document_folder_id = $folder_id,
document_updated_by = 0
WHERE document_id = $document_id
AND document_client_id = $client_id
LIMIT 1"
);
// For API: treat success as "updated row" OR "query ran but values unchanged"
if (mysqli_errno($mysqli) === 0) {
$update_count = 1;
}
// Logging
logAudit("Document", "Edit", "$name_db via API ($api_key_name), previous version kept", $client_id, $document_id);
logAudit("API", "Success", "Edited document $name_db via API ($api_key_name)", $client_id);
} else {
// Not found (or not this client's doc)
$update_count = false;
logAudit("API", "Error", "Document update failed (not found or unauthorized) via API ($api_key_name)", $client_id);
}
}
// Output
require_once '../update_output.php';