Files
Fedor ac7467f0b4 Major CRM updates: AI Assistant, Court Status API, S3 integration improvements, and extensive file storage system
- Added comprehensive AI Assistant system (aiassist/ directory):
  * Vector search and embedding capabilities
  * Typebot proxy integration
  * Elastic search functionality
  * Message classification and chat history
  * MCP proxy for external integrations

- Implemented Court Status API (GetCourtStatus.php):
  * Real-time court document status checking
  * Integration with external court systems
  * Comprehensive error handling and logging

- Enhanced S3 integration:
  * Improved file backup system with metadata
  * Batch processing capabilities
  * Enhanced error logging and recovery
  * Copy operations with URL fixing

- Added Telegram contact creation API
- Improved error logging across all modules
- Enhanced callback system for AI responses
- Extensive backup file storage with timestamps
- Updated documentation and README files

- File storage improvements:
  * Thousands of backup files with proper metadata
  * Fix operations for broken file references
  * Project-specific backup and recovery systems
  * Comprehensive file integrity checking

Total: 26,461+ files added/modified including AWS SDK, vendor dependencies, and extensive backup system.
2025-10-16 11:17:21 +03:00

434 lines
14 KiB
PHP

<?php
/*+***********************************************************************************
* The contents of this file are subject to the vtiger CRM Public License Version 1.0
* ("License"); You may not use this file except in compliance with the License
* The Original Code is: vtiger CRM Open Source
* The Initial Developer of the Original Code is vtiger.
* Portions created by vtiger are Copyright (C) vtiger.
* All Rights Reserved.
*************************************************************************************/
/**
* ModComments Record Model
*/
class ModComments_Record_Model extends Vtiger_Record_Model {
/**
* Functions gets the comment id
*/
public function getId() {
//TODO : check why is modcommentsid is not set
$id = $this->get('modcommentsid');
if(empty($id)) {
return $this->get('id');
}
return $this->get('modcommentsid');
}
public function setId($id) {
return $this->set('modcommentsid', $id);
}
/**
* Function returns url to get child comments
* @return <String> - url
*/
public function getChildCommentsUrl() {
return $this->getDetailViewUrl().'&mode=showChildComments';
}
public function addBlockQuotes(){
$content = $this->get('commentcontent');
$doc = new DOMDocument();
$urls = array();
if(!empty($content)){
//handling utf8 characters present in the template source
$formattedContent = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
$doc->loadHTML($formattedContent);
$body = $doc->getElementsByTagName('body');
$body = $body->item(0);
}
}
/**
* Funtion returns the fi
* @param type $recordId
* @return type
*/
public function getFileNameAndDownloadURL($recordId = false,$attachmentId = false){
if(empty($recordId))
$recordId = $this->get('modcommentsid');
$this->set('id',$recordId);
$fileDetails = $this->getFileDetails($attachmentId);
$attachmentDetails = array();
if(!empty($fileDetails)){
if(is_array($fileDetails[0])){
foreach($fileDetails as $index => $fileDetail){
if(!empty($fileDetail)){
$rawFileName = $fileDetail['name'];
$attachmentDetails[$index]['rawFileName'] = $rawFileName;
$attachmentDetails[$index]['attachmentId'] = $fileDetail['attachmentsid'];
$attachmentDetails[$index]['trimmedFileName'] = $this->trimFileName($rawFileName);
$attachmentDetails[$index]['url'] = 'index.php?module=ModComments&action=DownloadFile&record='. $recordId .'&fileid='. $fileDetail['attachmentsid'];
}
}
}
}
return $attachmentDetails;
}
/**
* Function trims the file name after 15 characters
* given in configuration editor
* @param string $fileName
* @return string
*/
public function trimFileName($fileName = false){
if(!empty($fileName)){
$fileDetails = explode('.',$fileName);
$noOfParts = count($fileDetails);
$fileExtension = $fileDetails[$noOfParts-1];
$val = str_replace(".$fileExtension", '', $fileName);
$field_val = $val;
$listview_max_textlength = 50;
global $default_charset;
$temp_val = preg_replace("/(<\/?)(\w+)([^>]*>)/i", "", $field_val);
if (function_exists('mb_strlen')) {
if (mb_strlen(decode_html($temp_val)) > $listview_max_textlength) {
$temp_val = mb_substr(preg_replace("/(<\/?)(\w+)([^>]*>)/i", "", decode_html($field_val)), 0, $listview_max_textlength, $default_charset) . '...';
}
} elseif (strlen(html_entity_decode($field_val)) > $listview_max_textlength) {
$temp_val = substr(preg_replace("/(<\/?)(\w+)([^>]*>)/i", "", $field_val), 0, $listview_max_textlength) . '...';
}
$fileName = $temp_val.'.'.$fileExtension;
}
return $fileName;
}
public function getImagePath() {
$commentor = $this->getCommentedByModel();
$isMailConverterType = $this->get('from_mailconverter');
if($commentor) {
$customer = $this->get('customer');
if (!empty($customer)) {
$recordModel = Vtiger_Record_Model::getInstanceById($customer);
$imageDetails = $recordModel->getImageDetails();
if(!empty($imageDetails)) {
return $imageDetails[0]['path'].'_'.$imageDetails[0]['name'];
} else
return vimage_path('CustomerPortal.png');
} else {
$imagePath = $commentor->getImageDetails();
if (!empty($imagePath[0]['name'])) {
return $imagePath[0]['path'] . '_' . $imagePath[0]['name'];
}
}
} elseif ($isMailConverterType) {
return vimage_path('MailConverterComment.png');
}
return false;
}
/**
* Function to create an instance of ModComment_Record_Model
* @param <Integer> $record
* @return ModComment_Record_Model
*/
public static function getInstanceById($record, $module=null) {
$db = PearDatabase::getInstance();
$result = $db->pquery('SELECT vtiger_modcomments.*, vtiger_crmentity.smownerid,
vtiger_crmentity.createdtime, vtiger_crmentity.modifiedtime FROM vtiger_modcomments
INNER JOIN vtiger_crmentity ON vtiger_modcomments.modcommentsid = vtiger_crmentity.crmid
WHERE modcommentsid = ? AND deleted = 0', array($record));
if($db->num_rows($result)) {
$row = $db->query_result_rowdata($result, $i);
$self = new self();
$self->setData($row);
return $self;
}
return false;
}
/**
* Function returns the parent Comment Model
* @return <Vtiger_Record_Model>
*/
public function getParentCommentModel() {
$recordId = $this->get('parent_comments');
if(!empty($recordId))
return ModComments_Record_Model::getInstanceById($recordId, 'ModComments');
return false;
}
/**
* Function returns the parent Record Model(Contacts, Accounts etc)
* @return <Vtiger_Record_Model>
*/
public function getParentRecordModel() {
$parentRecordId = $this->get('related_to');
if(!empty($parentRecordId))
return Vtiger_Record_Model::getInstanceById($parentRecordId);
return false;
}
/**
* Function returns the commentor Model (Users Model)
* @return <Vtiger_Record_Model>
*/
public function getCommentedByModel() {
$customer = $this->get('customer');
if(!empty($customer)) {
try {
return Vtiger_Record_Model::getInstanceById($customer, 'Contacts');
} catch(Exception $e) {
return false;
}
} else {
$commentedBy = $this->get('smownerid');
if($commentedBy) {
$commentedByModel = Vtiger_Record_Model::getInstanceById($commentedBy, 'Users');
if(empty($commentedByModel->entity->column_fields['user_name'])) {
$activeAdmin = Users::getActiveAdminUser();
$commentedByModel = Vtiger_Record_Model::getInstanceById($activeAdmin->id, 'Users');
}
return $commentedByModel;
}
}
return false;
}
/**
* Function returns the commented time
* @return <String>
*/
public function getCommentedTime() {
$commentTime = $this->get('createdtime');
return $commentTime;
}
/**
* Function returns the commented time
* @return <String>
*/
public function getModifiedTime() {
$commentTime = $this->get('modifiedtime');
return $commentTime;
}
/**
* Function returns latest comments for parent record
* @param <Integer> $parentRecordId - parent record for which latest comment need to retrieved
* @param <Vtiger_Paging_Model> - paging model
* @return ModComments_Record_Model if exits or null
*/
public static function getRecentComments($parentRecordId, $pagingModel = false){
$recordInstances = array();
$db = PearDatabase::getInstance();
$listView = Vtiger_ListView_Model::getInstance('ModComments');
$queryGenerator = $listView->get('query_generator');
$queryGenerator->setFields(array('parent_comments', 'createdtime', 'modifiedtime', 'related_to', 'assigned_user_id',
'commentcontent', 'creator', 'id', 'customer', 'reasontoedit', 'userid', 'from_mailconverter', 'from_mailroom', 'is_private', 'customer_email', 'related_email_id', 'filename'));
$query = $queryGenerator->getQuery();
$query = $query ." AND related_to = ? ORDER BY vtiger_crmentity.createdtime DESC";
if($pagingModel){
$startIndex = $pagingModel->getStartIndex();
$limit = $pagingModel->getPageLimit();
$limit = $limit+1;
$query = $query . " LIMIT $startIndex, $limit";
}
$result = $db->pquery($query, array($parentRecordId));
$rows = $db->num_rows($result);
for ($i=0; $i<$rows; $i++) {
$row = $db->query_result_rowdata($result, $i);
$recordInstance = new self();
$recordInstance->setData($row);
$recordInstances[] = $recordInstance;
}
return $recordInstances;
}
/**
* Function returns all the parent comments model
* @param <Integer> $parentId
* @return ModComments_Record_Model(s)
*/
public static function getAllParentComments($parentId) {
$db = PearDatabase::getInstance();
$focus = CRMEntity::getInstance('ModComments');
$query = $focus->get_comments();
if($query) {
$query .= " AND related_to = ? AND parent_comments = ? ORDER BY vtiger_crmentity.createdtime DESC";
$result = $db->pquery($query, array($parentId, ''));
$count = $db->num_rows($result);
for($i = 0; $i < $count; $i++) {
$rowData = $db->query_result_rowdata($result, $i);
$recordInstance = new self();
$recordInstance->setData($rowData);
$recordInstances[] = $recordInstance;
}
return $recordInstances;
} else {
return array();
}
}
/**
* Function returns all the child comment count
* @return <type>
*/
public function getChildCommentsCount() {
$db = PearDatabase::getInstance();
$parentRecordId = $this->get('related_to');
$query = 'SELECT 1 FROM vtiger_modcomments WHERE parent_comments = ? AND related_to = ?';
$result = $db->pquery($query, array($this->getId(), $parentRecordId));
if($db->num_rows($result)) {
return $db->num_rows($result);
} else {
return 0;
}
}
/**
* Returns child comments models for a comment
* @return ModComment_Record_Model(s)
*/
public function getChildComments() {
$db = PearDatabase::getInstance();
$parentCommentId = $this->get('modcommentsid');
if(empty($parentCommentId)) return;
$parentRecordId = $this->get('related_to');
$listView = Vtiger_ListView_Model::getInstance('ModComments');
$queryGenerator = $listView->get('query_generator');
$queryGenerator->setFields(array('parent_comments', 'createdtime', 'modifiedtime', 'related_to', 'id', 'assigned_user_id',
'commentcontent', 'creator', 'reasontoedit', 'userid', 'from_mailconverter', 'from_mailroom','is_private', 'customer_email'));
$query = $queryGenerator->getQuery();
//Condition are directly added as query_generator transforms the
//reference field and searches their entity names
$query = $query. ' AND parent_comments = ? AND related_to = ?';
$recordInstances = array();
$result = $db->pquery($query, array($parentCommentId, $parentRecordId));
$rows = $db->num_rows($result);
for ($i=0; $i<$rows; $i++) {
$row = $db->query_result_rowdata($result, $i);
$recordInstance = new self();
$recordInstance->setData($row);
$recordInstances[] = $recordInstance;
}
return $recordInstances;
}
/**
* Function to get details for user have the permissions to do actions
* @return <Boolean> - true/false
*/
public function isEditable() {
return false;
}
/**
* Function to get details for user have the permissions to do actions
* @return <Boolean> - true/false
*/
public function isDeletable() {
return false;
}
public function getCommentedByName() {
$customer = $this->get('customer');
$customerEmail = $this->get('customer_email');
$fromMailConverter = $this->get('from_mailconverter');
$fromMailroom = $this->get('from_mailroom');
if($customer && !empty($customer)) {
$label = Vtiger_Util_Helper::getRecordName($customer);
if(!$label)
$label = $customerEmail;
return $label;
} else if(($fromMailConverter || $fromMailroom) && $customerEmail && !empty($customerEmail)) {
return $customerEmail;
} else {
$commentedByModel = $this->getCommentedByModel();
return $commentedByModel->getName();
}
}
/**
* Function to get all comments related to record $parentId
* @param <Integer> $parentId
* @return ModComments_Record_Model(s)
*/
static function getAllComments($parentId) {
$db = PearDatabase::getInstance();
$focus = CRMEntity::getInstance('ModComments');
$query = $focus->get_comments();
if($query) {
$query .= " AND related_to = ? ORDER BY vtiger_crmentity.createdtime DESC";
$result = $db->pquery($query, array($parentId));
$count = $db->num_rows($result);
for($i = 0; $i < $count; $i++) {
$rowData = $db->query_result_rowdata($result, $i);
$recordInstance = new self();
$recordInstance->setData($rowData);
$recordInstances[] = $recordInstance;
}
return $recordInstances;
} else {
return array();
}
}
function uploadAndSaveFile($emailId,$attachmentId) {
$db = PearDatabase::getInstance();
$db->pquery('INSERT INTO vtiger_seattachmentsrel(crmid,attachmentsid) VALUES(?,?)',array($emailId,$attachmentId));
}
function getAttachmentDetails() {
$db = PearDatabase::getInstance();
$attachmentRes = $db->pquery("SELECT * FROM vtiger_attachments
INNER JOIN vtiger_seattachmentsrel ON vtiger_attachments.attachmentsid = vtiger_seattachmentsrel.attachmentsid
WHERE vtiger_seattachmentsrel.crmid = ?", array($this->getId()));
$numOfRows = $db->num_rows($attachmentRes);
$attachmentsList = array();
if($numOfRows) {
for($i=0; $i<$numOfRows; $i++) {
$attachmentsList[$i]['fileid'] = $db->query_result($attachmentRes, $i, 'attachmentsid');
$attachmentsList[$i]['attachment'] = decode_html($db->query_result($attachmentRes, $i, 'name'));
$path = $db->query_result($attachmentRes, $i, 'path');
$attachmentsList[$i]['path'] = $path;
$attachmentsList[$i]['size'] = filesize($path.$attachmentsList[$i]['fileid'].'_'.$attachmentsList[$i]['attachment']);
$attachmentsList[$i]['type'] = $db->query_result($attachmentRes, $i, 'type');
$attachmentsList[$i]['cid'] = $db->query_result($attachmentRes, $i, 'cid');
}
}
return $attachmentsList;
}
public function getParsedContent(){
require_once 'modules/Settings/MailConverter/handlers/MailParser.php';
$htmlParser = new Vtiger_MailParser($this->getName());
return $htmlParser->parseHtml();
}
}