Save all currently accumulated repository changes as a backup snapshot for Gitea so no local work is lost.
362 lines
17 KiB
PHP
362 lines
17 KiB
PHP
<?php
|
||
/*********************************************************************************
|
||
* Endpoint для добавления комментария из мини-приложения.
|
||
* Куда писать: contact_id → к контакту; ticket_id → к заявке (HelpDesk); project_id → к проекту.
|
||
* Передаётся ровно один из них (при нескольких — приоритет: ticket_id > project_id > contact_id).
|
||
* Вход: JSON — объект или массив { "message" (обяз.) + один из contact_id / ticket_id / project_id }.
|
||
* Опционально: contact_id как автор (customer); file_id, mime_type, file_size, filename, botname.
|
||
* Канал: miniapp.
|
||
********************************************************************************/
|
||
|
||
error_reporting(E_ALL);
|
||
ini_set('display_errors', '1');
|
||
include_once 'modules/Users/Users.php';
|
||
include_once 'include/utils/CommonUtils.php';
|
||
include_once 'include/utils/utils.php';
|
||
require_once('include/Webservices/Utils.php');
|
||
require_once 'include/Webservices/Create.php';
|
||
require_once 'include/Webservices/Revise.php';
|
||
require_once 'include/utils/WhatsApp.php';
|
||
require_once 'includes/Loader.php';
|
||
|
||
vimport ('includes.runtime.Globals');
|
||
vimport ('includes.runtime.BaseModel');
|
||
vimport ('includes.runtime.LanguageHandler');
|
||
|
||
$str = file_get_contents('php://input');
|
||
$logstring = date('Y-m-d H:i:s').' '.$str.PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
|
||
$input = json_decode($str, true);
|
||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||
$logstring = date('Y-m-d H:i:s').' Ошибка парсинга JSON: '.json_last_error_msg().PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
echo json_encode(array('success' => false, 'error' => 'Invalid JSON'));
|
||
exit;
|
||
}
|
||
|
||
// Единообразно: всегда массив элементов
|
||
if (isset($input['message']) && (isset($input['contact_id']) || isset($input['ticket_id']) || isset($input['ticketid']) || isset($input['project_id']))) {
|
||
$items = array($input);
|
||
} else {
|
||
$items = is_array($input) ? $input : array();
|
||
}
|
||
if (!is_array($items) || empty($items)) {
|
||
$logstring = date('Y-m-d H:i:s').' Ожидается объект или массив с message и одним из: contact_id, ticket_id, project_id'.PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
echo json_encode(array('success' => false, 'error' => 'Expected message + one of contact_id, ticket_id, project_id'));
|
||
exit;
|
||
}
|
||
|
||
global $adb;
|
||
$user = Users::getActiveAdminUser();
|
||
|
||
$allowed_types = array(
|
||
'text/plain',
|
||
'image', 'image/png', 'image/jpeg', 'image/jpg',
|
||
'application/pdf',
|
||
'application/msword', 'application/excel', 'application/vnd.ms-excel',
|
||
'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet',
|
||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
);
|
||
$images = array('image', 'image/png', 'image/jpeg', 'image/jpg');
|
||
|
||
$all_bot_tokens = array(
|
||
'klientprav_bot' => '6118440594:AAGpqeudXF9wHSZ7vpAsXQ4Jp5XXlUoqB1A',
|
||
'lexpriority_bot' => '6631721508:AAG0FIXhlprPGeeb_6zh5gjOpNdWzSWIRS8',
|
||
'clientright_bot' => '7919885676:AAEPfOt-oLl2rR1FhlGDd_yqk6ScXJr43T0'
|
||
);
|
||
|
||
|
||
$results = array();
|
||
foreach ($items as $idx => $data) {
|
||
$contact_id = isset($data['contact_id']) ? (int)$data['contact_id'] : 0;
|
||
$ticket_id = isset($data['ticket_id']) ? (int)$data['ticket_id'] : (isset($data['ticketid']) ? (int)$data['ticketid'] : 0);
|
||
$project_id = isset($data['project_id']) ? (int)$data['project_id'] : 0;
|
||
$message = isset($data['message']) ? $data['message'] : '';
|
||
|
||
// Куда вешаем комментарий: приоритет ticket_id > project_id > contact_id
|
||
if ($ticket_id > 0) {
|
||
$related_to = '6x' . $ticket_id;
|
||
$target_type = 'HelpDesk';
|
||
$target_id = $ticket_id;
|
||
} elseif ($project_id > 0) {
|
||
$related_to = '33x' . $project_id;
|
||
$target_type = 'Project';
|
||
$target_id = $project_id;
|
||
} elseif ($contact_id > 0) {
|
||
$related_to = '12x' . $contact_id;
|
||
$target_type = 'Contacts';
|
||
$target_id = $contact_id;
|
||
} else {
|
||
$results[] = array('success' => false, 'error' => 'Required one of contact_id, ticket_id, project_id');
|
||
continue;
|
||
}
|
||
|
||
if ($message === '' && !isset($data['file_id']) && empty($data['url']) && empty($data['newfile'])) {
|
||
$results[] = array('success' => false, 'target_type' => $target_type, 'target_id' => $target_id, 'error' => 'message or file_id required');
|
||
continue;
|
||
}
|
||
|
||
// Текст комментария и проверка файла (как в telegram.php)
|
||
$msg = '';
|
||
$file_id = isset($data['file_id']) ? $data['file_id'] : null;
|
||
$external_url = isset($data['url']) ? trim($data['url']) : '';
|
||
$external_newfile = isset($data['newfile']) ? trim($data['newfile']) : '';
|
||
if ($external_url === '' && $external_newfile !== '' && preg_match('#^https?://#i', $external_newfile)) {
|
||
$external_url = $external_newfile;
|
||
}
|
||
$external_filename = isset($data['file_name']) ? $data['file_name'] : (isset($data['filename']) ? $data['filename'] : '');
|
||
$mime_type = isset($data['mime_type']) ? $data['mime_type'] : '';
|
||
$file_size = isset($data['file_size']) ? (int)$data['file_size'] : 0;
|
||
$filename = isset($data['filename']) ? $data['filename'] : 'file';
|
||
$botname = isset($data['botname']) ? $data['botname'] : 'clientright_bot';
|
||
if (!array_key_exists($botname, $all_bot_tokens)) {
|
||
$botname = 'clientright_bot';
|
||
}
|
||
|
||
if ($file_id) {
|
||
if ($file_size > 5242880) {
|
||
$msg = 'Передан файл более 5 мб - НЕ загружен!';
|
||
} elseif (!in_array($mime_type, $allowed_types)) {
|
||
$msg = 'Передан файл недопустимого формата - НЕ загружен!';
|
||
}
|
||
if (!isset($message) || $message === '') {
|
||
$message = $msg !== '' ? $msg : 'Файл во вложении';
|
||
} elseif ($msg !== '') {
|
||
$message .= PHP_EOL.'======='.PHP_EOL.$msg;
|
||
}
|
||
} elseif ($external_url !== '' || $external_newfile !== '') {
|
||
if (!isset($message) || $message === '') {
|
||
$message = 'Файл во вложении';
|
||
}
|
||
}
|
||
|
||
try {
|
||
$params = array(
|
||
'commentcontent' => $message,
|
||
'related_to' => $related_to,
|
||
'channel' => 'miniapp',
|
||
'assigned_user_id' => $user
|
||
);
|
||
$logstring = date('Y-m-d H:i:s').' [miniapp] Параметры для vtws_create: '.json_encode($params).PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
|
||
$comment = vtws_create('ModComments', $params, $user);
|
||
$commentid = (int)substr($comment['id'], 3);
|
||
|
||
$logstring = date('Y-m-d H:i:s').' [miniapp] Ответ API (id, channel в ответе): id='.($comment['id'] ?? '?').', channel='.(isset($comment['channel']) ? $comment['channel'] : '(нет в ответе)').PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
|
||
// Явно пишем channel в БД (vtws_create может не сохранить поле, если оно не в маппинге модуля)
|
||
$adb->pquery('UPDATE vtiger_modcomments SET channel = ? WHERE modcommentsid = ?', array('miniapp', $commentid));
|
||
$logstring = date('Y-m-d H:i:s').' [miniapp] Выполнен UPDATE vtiger_modcomments SET channel=miniapp WHERE modcommentsid='.$commentid.PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
|
||
// Проверка: что реально записалось в БД по channel
|
||
$check = $adb->pquery('SELECT modcommentsid, channel, commentcontent FROM vtiger_modcomments WHERE modcommentsid = ?', array($commentid));
|
||
if ($adb->num_rows($check) > 0) {
|
||
$row_channel = $adb->query_result($check, 0, 'channel');
|
||
$logstring = date('Y-m-d H:i:s').' [miniapp] Проверка БД: modcommentsid='.$commentid.' channel='.var_export($row_channel, true).PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
} else {
|
||
$logstring = date('Y-m-d H:i:s').' [miniapp] Проверка БД: запись modcommentsid='.$commentid.' не найдена'.PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
}
|
||
|
||
if ($contact_id > 0) {
|
||
$query = 'UPDATE vtiger_modcomments SET customer = ?, userid = 0 WHERE modcommentsid = ?';
|
||
$adb->pquery($query, array($contact_id, $commentid));
|
||
}
|
||
|
||
$logstring = date('Y-m-d H:i:s').' Коммент к '.$target_type.' '.$target_id.' создан, commentid='.$commentid.PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
|
||
// Вложение: скачать по прямой ссылке (S3) и привязать к комментарию
|
||
if ($external_url !== '' && $msg === '') {
|
||
$filename_from_url = '';
|
||
$parsed_path = parse_url($external_url, PHP_URL_PATH);
|
||
if (!empty($parsed_path)) {
|
||
$filename_from_url = basename($parsed_path);
|
||
}
|
||
$filename_to_use = $external_filename !== '' ? $external_filename : ($filename_from_url !== '' ? $filename_from_url : 'file');
|
||
|
||
$context = stream_context_create(array('http' => array('timeout' => 20)));
|
||
$file_data = @file_get_contents($external_url, false, $context);
|
||
if ($file_data === false) {
|
||
$logstring = date('Y-m-d H:i:s').' [miniapp] Не удалось скачать файл по URL: '.$external_url.PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
} else {
|
||
$current_id = $adb->getUniqueID("vtiger_crmentity");
|
||
$date_var = date('Y-m-d H:i:s');
|
||
$ownerid = $user;
|
||
if ($contact_id > 0) {
|
||
$ownerRes = $adb->pquery('SELECT smownerid FROM vtiger_crmentity WHERE crmid = ? AND deleted = 0', array($contact_id));
|
||
$ownerid = $adb->num_rows($ownerRes) ? $adb->query_result($ownerRes, 0, 'smownerid') : $user;
|
||
$ownerid = getUserIdMiniapp($ownerid, $contact_id);
|
||
} else {
|
||
$ownerRes = $adb->pquery('SELECT smownerid FROM vtiger_crmentity WHERE crmid = ? AND deleted = 0', array($target_id));
|
||
$ownerid = $adb->num_rows($ownerRes) ? $adb->query_result($ownerRes, 0, 'smownerid') : $user;
|
||
}
|
||
$upload_file_path = decideFilePath();
|
||
$full_path = $upload_file_path . $current_id . "_" . $filename_to_use;
|
||
file_put_contents($full_path, $file_data);
|
||
|
||
$detected_mime = $mime_type;
|
||
if ($detected_mime === '' || $detected_mime === 'application/octet-stream') {
|
||
$detected_mime = @mime_content_type($full_path);
|
||
}
|
||
if (!$detected_mime) {
|
||
$detected_mime = 'application/octet-stream';
|
||
}
|
||
|
||
if (in_array($detected_mime, $images) || strpos($detected_mime, 'image/') === 0) {
|
||
$PDFPath = jpg2pdf($full_path);
|
||
@unlink($full_path);
|
||
$file_parts = pathinfo($filename_to_use);
|
||
$filename_to_use = (isset($file_parts['filename']) ? $file_parts['filename'] : 'file') . '.pdf';
|
||
$detected_mime = 'application/pdf';
|
||
$full_path = $PDFPath;
|
||
}
|
||
|
||
$adb->pquery(
|
||
"INSERT INTO vtiger_crmentity (crmid, smcreatorid, smownerid, setype, createdtime, modifiedtime) VALUES (?,?,?,?,?,?)",
|
||
array($current_id, $ownerid, $ownerid, 'ModComments Attachment', $adb->formatDate($date_var, true), $adb->formatDate($date_var, true))
|
||
);
|
||
$adb->pquery(
|
||
"INSERT INTO vtiger_attachments(attachmentsid, name, type, path, storedname) VALUES (?,?,?,?,?)",
|
||
array($current_id, $filename_to_use, $detected_mime, $upload_file_path, $filename_to_use)
|
||
);
|
||
$adb->pquery("INSERT INTO vtiger_seattachmentsrel(crmid, attachmentsid) VALUES (?,?)", array($commentid, $current_id));
|
||
$adb->pquery('UPDATE vtiger_modcomments SET filename = ? WHERE modcommentsid = ?', array($current_id, $commentid));
|
||
}
|
||
}
|
||
|
||
// Вложение: скачать через Telegram API и привязать к комментарию (как в telegram.php)
|
||
$file_path = null;
|
||
$bot_token = $all_bot_tokens[$botname];
|
||
if ($file_id && $msg === '') {
|
||
$tokens_to_try = array();
|
||
if (isset($all_bot_tokens[$botname])) {
|
||
$tokens_to_try[] = array('name' => $botname, 'token' => $all_bot_tokens[$botname]);
|
||
}
|
||
foreach ($all_bot_tokens as $name => $token) {
|
||
if ($name !== $botname) {
|
||
$tokens_to_try[] = array('name' => $name, 'token' => $token);
|
||
}
|
||
}
|
||
|
||
foreach ($tokens_to_try as $bot_info) {
|
||
$try_token = $bot_info['token'];
|
||
$try_name = $bot_info['name'];
|
||
$url = 'https://api.telegram.org/bot'.$try_token.'/getFile';
|
||
$curl = curl_init();
|
||
curl_setopt($curl, CURLOPT_URL, $url);
|
||
curl_setopt($curl, CURLOPT_POST, true);
|
||
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
|
||
curl_setopt($curl, CURLOPT_POSTFIELDS, array('file_id' => $file_id));
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||
$output = curl_exec($curl);
|
||
$output = json_decode($output, true);
|
||
curl_close($curl);
|
||
|
||
if (!empty($output['ok'])) {
|
||
$file_path = $output['result']['file_path'];
|
||
$bot_token = $try_token;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if ($file_path) {
|
||
$url = 'https://api.telegram.org/file/bot'.$bot_token.'/'.$file_path;
|
||
$current_id = $adb->getUniqueID("vtiger_crmentity");
|
||
$date_var = date('Y-m-d H:i:s');
|
||
$ownerid = $user;
|
||
if ($contact_id > 0) {
|
||
$ownerRes = $adb->pquery('SELECT smownerid FROM vtiger_crmentity WHERE crmid = ? AND deleted = 0', array($contact_id));
|
||
$ownerid = $adb->num_rows($ownerRes) ? $adb->query_result($ownerRes, 0, 'smownerid') : $user;
|
||
$ownerid = getUserIdMiniapp($ownerid, $contact_id);
|
||
} else {
|
||
$ownerRes = $adb->pquery('SELECT smownerid FROM vtiger_crmentity WHERE crmid = ? AND deleted = 0', array($target_id));
|
||
$ownerid = $adb->num_rows($ownerRes) ? $adb->query_result($ownerRes, 0, 'smownerid') : $user;
|
||
}
|
||
$upload_file_path = decideFilePath();
|
||
|
||
if ($filename === 'image') {
|
||
$slash = strpos($file_path, '/');
|
||
$filename = $slash !== false ? substr($file_path, $slash + 1) : 'image.jpg';
|
||
}
|
||
file_put_contents($upload_file_path . $current_id . "_" . $filename, file_get_contents($url));
|
||
|
||
if (in_array($mime_type, $images)) {
|
||
$PDFPath = jpg2pdf($upload_file_path . $current_id . "_" . $filename);
|
||
unlink($upload_file_path . $current_id . "_" . $filename);
|
||
$file_parts = pathinfo($filename);
|
||
$filename = (isset($file_parts['filename']) ? $file_parts['filename'] : 'file') . '.pdf';
|
||
$mime_type = 'application/pdf';
|
||
}
|
||
|
||
$adb->pquery(
|
||
"INSERT INTO vtiger_crmentity (crmid, smcreatorid, smownerid, setype, createdtime, modifiedtime) VALUES (?,?,?,?,?,?)",
|
||
array($current_id, $ownerid, $ownerid, 'ModComments Attachment', $adb->formatDate($date_var, true), $adb->formatDate($date_var, true))
|
||
);
|
||
$adb->pquery(
|
||
"INSERT INTO vtiger_attachments(attachmentsid, name, type, path, storedname) VALUES (?,?,?,?,?)",
|
||
array($current_id, $filename, $mime_type, $upload_file_path, $filename)
|
||
);
|
||
$adb->pquery("INSERT INTO vtiger_seattachmentsrel(crmid, attachmentsid) VALUES (?,?)", array($commentid, $current_id));
|
||
$adb->pquery('UPDATE vtiger_modcomments SET filename = ? WHERE modcommentsid = ?', array($current_id, $commentid));
|
||
}
|
||
}
|
||
|
||
// Всплывашка: уведомление ответственного за сущность (тикет / проект / контакт)
|
||
$ownerRes = $adb->pquery('SELECT smownerid FROM vtiger_crmentity WHERE crmid = ? AND deleted = 0', array($target_id));
|
||
$userid_owner = $adb->num_rows($ownerRes) ? $adb->query_result($ownerRes, 0, 'smownerid') : null;
|
||
if ($userid_owner) {
|
||
if ($target_type === 'HelpDesk') {
|
||
$link = 'module=HelpDesk&view=Detail&record='.$target_id.'&app=SUPPORT';
|
||
} elseif ($target_type === 'Project') {
|
||
$link = 'module=Project&view=Detail&record='.$target_id.'&app=SUPPORT';
|
||
} else {
|
||
$link = 'module=Contacts&view=Detail&record='.$target_id.'&app=MARKETING';
|
||
}
|
||
$title = 'Новое сообщение (miniapp)';
|
||
$exist = $adb->pquery('SELECT id FROM vtiger_vdnotifierpro WHERE userid = ? AND crmid = ? AND title = ? AND status = 5', array($userid_owner, $target_id, $title));
|
||
if ($adb->num_rows($exist) > 0) {
|
||
$adb->pquery('UPDATE vtiger_vdnotifierpro SET modifiedtime = ? WHERE id = ?', array(date('Y-m-d H:i:s'), $adb->query_result($exist, 0, 'id')));
|
||
} else {
|
||
$adb->pquery(
|
||
'INSERT INTO vtiger_vdnotifierpro (userid, modulename, crmid, modiuserid, link, title, action, modifiedtime, status) VALUES (?,?,?,0,?,?,?,?,5)',
|
||
array($userid_owner, $target_type, $target_id, $link, $title, '', date('Y-m-d H:i:s'))
|
||
);
|
||
}
|
||
}
|
||
|
||
$results[] = array('success' => true, 'target_type' => $target_type, 'target_id' => $target_id, 'comment_id' => $commentid);
|
||
} catch (WebServiceException $ex) {
|
||
$logstring = date('Y-m-d H:i:s').' Ошибка: '.$ex->getMessage().PHP_EOL;
|
||
file_put_contents('logs/miniapp_msg.log', $logstring, FILE_APPEND);
|
||
$results[] = array('success' => false, 'target_type' => isset($target_type) ? $target_type : '', 'target_id' => isset($target_id) ? $target_id : 0, 'error' => $ex->getMessage());
|
||
}
|
||
}
|
||
|
||
header('Content-Type: application/json; charset=utf-8');
|
||
echo json_encode(array('success' => true, 'results' => $results));
|
||
|
||
function getUserIdMiniapp($userid, $contactid) {
|
||
global $adb;
|
||
$query = 'SELECT e.smownerid AS userid FROM vtiger_project p
|
||
LEFT JOIN vtiger_crmentity e ON e.crmid = p.projectid
|
||
WHERE e.deleted = 0 AND p.linktoaccountscontacts = ? AND p.projectstatus <> "completed"';
|
||
$result = $adb->pquery($query, array($contactid));
|
||
if ($adb->num_rows($result) === 1) {
|
||
return $adb->query_result($result, 0, 'userid');
|
||
}
|
||
return $userid;
|
||
}
|
||
|
||
?>
|