NOW() - INTERVAL " . SMS_CONVERSATION_DAYS . " DAY ORDER BY sms_message_id ASC LIMIT 20"), MYSQLI_ASSOC); $ids = array_map('intval', array_column($texts, 'sms_message_id')); if (!in_array(intval($row['sms_message_id']), $ids, true)) { $ids[] = intval($row['sms_message_id']); $texts[] = $row; } $words = []; $media = []; foreach ($texts as $text) { if (trim((string) $text['sms_message_body']) !== '') { $words[] = count($texts) > 1 ? date('M j, g:i A', strtotime($text['sms_message_created_at'])) . ":\n" . $text['sms_message_body'] : (string) $text['sms_message_body']; } $media = array_merge($media, $text['sms_message_media'] ? (json_decode($text['sms_message_media'], true) ?: []) : []); } $ticket_id = smsTicketOpen(intval($row['sms_message_id']), $number, implode("\n\n", $words), array_slice($media, 0, SMS_MEDIA_MAX_FILES), $contact_id, $client_id, $subject, intval($session_user_id), $ids); mysqli_query($mysqli, "UPDATE sms_messages SET sms_message_status = 'ticket', sms_message_handled_at = NOW(), sms_message_handled_by = " . intval($session_user_id) . " WHERE sms_message_id IN (" . implode(',', $ids) . ")"); if (!empty($_POST['assign_me'])) { mysqli_query($mysqli, "UPDATE tickets SET ticket_assigned_to = " . intval($session_user_id) . ", ticket_status = 2 WHERE ticket_id = $ticket_id"); } // Their next text finds them - when they have no mobile yet $saved = ''; if ($contact && !empty($_POST['save_number']) && trim((string) $contact['contact_mobile']) === '' && smsNumberIsPhone($number)) { [$cc, $national] = smsNumberParts($number); mysqli_query($mysqli, "UPDATE contacts SET contact_mobile = '" . escapeSql($national) . "', contact_mobile_country_code = '" . escapeSql($cc) . "' WHERE contact_id = $contact_id"); $saved = ' - ' . smsNumberText($number) . ' saved as ' . $contact['contact_name'] . '\'s mobile'; } $reference = ticketReference(ticketRow($ticket_id)); logAudit("Text Message", "Edit", "$session_name opened ticket " . escapeSql($reference) . " from " . count($ids) . " text" . (count($ids) === 1 ? '' : 's') . " from " . escapeSql(smsNumberText($number) . $saved), $client_id, $ticket_id); flashAlert("Ticket " . escapeHtml($reference) . " opened from the text" . (count($ids) === 1 ? '' : 's') . escapeHtml($saved) . " - Text reply on it texts them back"); redirect('/agent/' . ticketUrl($ticket_id, $client_id)); } // Ask a contact by text whether texts about their work are all right - a YES turns them on if (isset($_GET['sms_ask_opt_in'])) { validateCSRFToken(); enforceUserPermission('module_client', 2); $contact_id = intval($_GET['sms_ask_opt_in']); $contact = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT contact_name, contact_client_id FROM contacts WHERE contact_id = $contact_id")); if (!$contact || !hasClientAccess($contact['contact_client_id'])) { flashAlert('That contact no longer exists.', 'error'); redirect(); } $asked = smsOptInAsk($contact_id, intval($session_user_id)); if (!$asked['ok']) { flashAlert('Not asked - ' . escapeHtml($asked['error']), 'error'); redirect(); } logAudit("Contact", "Edit", "$session_name asked " . escapeSql($contact['contact_name']) . " by text whether texts are all right", intval($contact['contact_client_id']), $contact_id); flashAlert('' . escapeHtml($contact['contact_name']) . ' asked by text - a YES turns texts on for them'); redirect(); } if (isset($_GET['sms_dismiss'])) { validateCSRFToken(); enforceUserPermission('module_support', 2); $row = textsForRequest($_GET['sms_dismiss'], ['unmatched']); mysqli_query($mysqli, "UPDATE sms_messages SET sms_message_status = 'dismissed', sms_message_handled_at = NOW(), sms_message_handled_by = " . intval($session_user_id) . " WHERE sms_message_id = " . intval($row['sms_message_id'])); logAudit("Text Message", "Edit", "$session_name dismissed a text from " . escapeSql(smsNumberText($row['sms_message_number'])), intval($row['sms_message_client_id'])); flashAlert('Text dismissed - it stays in the text log for ' . SMS_SPAM_KEEP_DAYS . ' days'); redirect(); } if (isset($_GET['sms_mark_spam'])) { validateCSRFToken(); enforceUserPermission('module_support', 2); $row = textsForRequest($_GET['sms_mark_spam'], ['unmatched']); $number = (string) $row['sms_message_number']; smsNumberSet($number, ['blocked_at' => 'NOW()', 'blocked_by' => intval($session_user_id)]); mysqli_query($mysqli, "UPDATE sms_messages SET sms_message_status = 'spam', sms_message_handled_at = NOW(), sms_message_handled_by = " . intval($session_user_id) . " WHERE sms_message_direction = 'in' AND sms_message_number = '" . escapeSql($number) . "' AND sms_message_status IN ('unmatched', 'dismissed')"); logAudit("Text Message", "Edit", "$session_name marked texts from " . escapeSql(smsNumberText($number)) . " as spam and blocked the number"); flashAlert('' . escapeHtml(smsNumberText($number)) . ' blocked - what it sends goes straight to Spam'); redirect(); } if (isset($_GET['sms_not_spam'])) { validateCSRFToken(); enforceUserPermission('module_support', 2); $row = textsForRequest($_GET['sms_not_spam'], ['spam']); $number = (string) $row['sms_message_number']; smsNumberSet($number, ['blocked_at' => null, 'blocked_by' => 0]); mysqli_query($mysqli, "UPDATE sms_messages SET sms_message_status = 'unmatched', sms_message_handled_at = NULL, sms_message_handled_by = 0 WHERE sms_message_direction = 'in' AND sms_message_number = '" . escapeSql($number) . "' AND sms_message_status = 'spam'"); logAudit("Text Message", "Edit", "$session_name said texts from " . escapeSql(smsNumberText($number) . " aren't spam") . " and unblocked the number"); flashAlert('' . escapeHtml(smsNumberText($number)) . ' isn\'t spam - its texts are in Unmatched'); redirect('texts.php?show=unmatched'); } if (isset($_GET['sms_delete'])) { validateCSRFToken(); enforceUserPermission('module_support', 2); $row = textsForRequest($_GET['sms_delete'], ['spam']); mysqli_query($mysqli, "DELETE FROM sms_messages WHERE sms_message_id = " . intval($row['sms_message_id'])); flashAlert('Text deleted', 'error'); redirect(); } if (isset($_GET['sms_not_code'])) { validateCSRFToken(); enforceUserPermission('module_credential', 2); $row = textsForRequest($_GET['sms_not_code'], ['code']); if ($row['sms_message_body'] === null) { flashAlert('Its words were wiped a day after it came.', 'error'); redirect(); } mysqli_query($mysqli, "UPDATE sms_messages SET sms_message_status = 'unmatched', sms_message_code = NULL WHERE sms_message_id = " . intval($row['sms_message_id'])); logAudit("Text Message", "Edit", "$session_name said a text from " . escapeSql(smsNumberText($row['sms_message_number']) . " isn't a code") . ", and moved it to Unmatched"); flashAlert('Moved to Unmatched'); redirect(); } if (isset($_POST['sms_label_number'])) { validateCSRFToken(); $row = smsMessageRow($_POST['id'] ?? 0); $code = $row && $row['sms_message_status'] === 'code'; if (!$row || $row['sms_message_direction'] !== 'in') { flashAlert('That text is gone.', 'error'); redirect('texts.php'); } enforceUserPermission($code ? 'module_credential' : 'module_support', $code ? 1 : 2); $number = (string) $row['sms_message_number']; $label = mb_substr(trim((string) ($_POST['label'] ?? '')), 0, 100); smsNumberSet($number, ['label' => $label !== '' ? $label : null]); logAudit("Text Message", "Edit", "$session_name " . ($label !== '' ? "named " . escapeSql(smsNumberText($number)) . " " . escapeSql($label) : "took the name off " . escapeSql(smsNumberText($number)))); flashAlert($label !== '' ? '' . escapeHtml(smsNumberText($number)) . ' is ' . escapeHtml($label) . ' now' : 'Name taken off'); redirect(); }