HEX
Server: Apache
System: Linux dev.epsylon.net 3.10.0-1160.144.1.el7.tuxcare.els2.x86_64 #1 SMP Sun Feb 15 11:22:42 UTC 2026 x86_64
User: nexper (1054)
PHP: 8.2.30
Disabled: exec,passthru,shell_exec,system
Upload Files
File: /home/nexper/public_html/crm/modules/AOD_Index/AOD_Index.php
<?PHP
/*********************************************************************************
 * SugarCRM Community Edition is a customer relationship management program developed by
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by the
 * Free Software Foundation with the addition of the following permission added
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License along with
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 * 
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 * these Appropriate Legal Notices must retain the display of the "Powered by
 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
 * technical reasons, the Appropriate Legal Notices must display the words
 * "Powered by SugarCRM".
 ********************************************************************************/

/**
 * THIS CLASS IS FOR DEVELOPERS TO MAKE CUSTOMIZATIONS IN
 */
require_once('modules/AOD_Index/AOD_Index_sugar.php');
require_once('modules/AOD_Index/LuceneUtils.php');
requireLucene();

class AOD_Index extends AOD_Index_sugar {
	
	function AOD_Index(){
		parent::AOD_Index_sugar();
	}

    function isEnabled(){
        global $sugar_config;
        return !empty($sugar_config['aod']['enable_aod']);
    }

    function find($queryString){
        $queryString = strtolower($queryString);
        $hits = $this->getLuceneIndex()->find($queryString);
        return $hits;
    }

    function optimise(){
        if(!$this->isEnabled()){
            return;
        }
        global $timedate;
        $this->getLuceneIndex()->optimize();
        $this->last_optimised = $timedate->getNow()->asDb();
        $this->save();
    }

    public function getIndex(){
        $indexes = $this->get_full_list();
        if(count($indexes)){
            $index = $indexes[0];
            return $index;
        }else{
            $index = new AOD_Index();
            $index->name = "Index";
            $index->location = "modules/AOD_Index/Index/Index";
            $index->save();
            return $index;
        }
    }

    /**
     * @param $revision
     * @return bool|Zend_Search_Lucene_Document
     */
private function getDocumentForRevision($revision){
    $path = getDocumentRevisionPath($revision->id);
    if(!file_exists($path)){
        return array("error"=>"File not found");
    }
    //Convert the file to a lucene document
    $mime = $revision->file_mime_type;
    switch($mime){
        case 'application/pdf':
            $document = createPDFDocument($path);
            break;
        case 'application/msword':
            $document = createDocDocument($path);
            break;
        case 'application/vnd.oasis.opendocument.text':
            $document = createOdtDocument($path);
            break;
        case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
            $document = createDocXDocument($path);
            break;
        case 'text/html':
            $document = createHTMLDocument($path);
            break;
        case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
            $document = createXLSXDocument($path);
            break;
        case 'application/rtf':
            $document = createRTFDocument($path);
        case 'text/csv':
        case 'text/plain':
            $document = createTextDocument($path);
            break;
        case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
            $document = createPPTXDocument($path);
            break;
        case 'application/vnd.oasis.opendocument.spreadsheet':
        case 'application/vnd.ms-powerpoint':
        case 'application/vnd.ms-excel':
        default:
            return array("error"=>"Mime type $mime not supported");
    }
    if(!$document){
        return array("error"=>"Failed to parse document");
    }
    $document->addField(Zend_Search_Lucene_Field::text("filename",$revision->filename));
    return array("error"=>false,"document"=>$document);
}

    public function getDocumentForBean(SugarBean $bean){
        if($bean->module_name == 'DocumentRevisions'){
            $document = $this->getDocumentForRevision($bean);
        }else{
            $document = array("error"=>false,"document"=>new Zend_Search_Lucene_Document());
        }
        if($document["error"]){
            return $document;
        }
        $document["document"]->addField(Zend_Search_Lucene_Field::UnIndexed("aod_id", $bean->module_name." ".$bean->id));
        $document["document"]->addField(Zend_Search_Lucene_Field::UnIndexed("record_id", $bean->id));
        $document["document"]->addField(Zend_Search_Lucene_Field::UnIndexed("record_module", $bean->module_name));
        foreach($GLOBALS['dictionary'][$bean->getObjectName()]['fields'] as $key => $field){
            switch($field['type']){
                case "enum":
                    $document["document"]->addField(Zend_Search_Lucene_Field::Keyword($key, strtolower($bean->$key)));
                    break;

                case "multienum":
                    $vals = unencodeMultienum($bean->$field);
                    $document["document"]->addField(Zend_Search_Lucene_Field::unStored($key, strtolower(implode(" ",$vals))));
                    break;
                case "name":
                case "phone":
                case "html":
                case "text":
                case "url":
                case "varchar":
                    if(property_exists($bean,$key)){
                        $val = strtolower($bean->$key);
                    }else{
                        $val = '';
                    }
                    $field = Zend_Search_Lucene_Field::unStored($key, $val);
                    if($key == "name"){
                        $field->boost = 1.5;
                    }
                    $document["document"]->addField($field);
                    break;
                case "address":
                case "bool":
                case "currency":
                case "date":
                case "datetimecombo":
                case "decimal":
                case "float":
                case "iframe":
                case "int":
                case "radioenum":
                case "relate":
                default:
                    break;
            }
        }

        return $document;
    }

    private function getIndexEvent($module, $beanId){
        $indexEventBean = BeanFactory::getBean("AOD_IndexEvent");
        $indexEvents = $indexEventBean->get_full_list('',"aod_indexevent.record_id = '".$beanId."' AND aod_indexevent.record_module = '".$module."'");
        if($indexEvents){
            $indexEvent = $indexEvents[0];
        }else{
            $indexEvent = BeanFactory::newBean("AOD_IndexEvent");
            $indexEvent->record_id = $beanId;
            $indexEvent->record_module = $module;
        }
        return $indexEvent;
    }

    public function commit(){
        if(!$this->isEnabled()){
            return;
        }
        $this->getLuceneIndex()->commit();
    }

    public static function isModuleSearchable($module,$beanName){
        $whiteList = array("DocumentRevisions","Cases");
        if(in_array($module,$whiteList)){
            return true;
        }
        $blackList = array("AOD_IndexEvent","AOD_Index","AOW_Actions","AOW_Conditions","AOW_Processed","SchedulersJobs");
        if(in_array($module,$blackList)){
            return false;
        }
        $manager = new VardefManager();
        $manager->loadVardef($module, $beanName);
        if(empty($GLOBALS['dictionary'][$beanName]['unified_search'])){
            return false;
        }
        return true;
    }

    public function index($module, $beanId){
        try{
            if(!$this->isEnabled()){
                return;
            }
            $bean_name = $GLOBALS['beanList'][$module];
            if(!$bean_name){
                return false;
            }
            $bean = new $bean_name();
            if(!$bean || ! $bean instanceof SugarBean){
                return false;
            }

            $bean->retrieve($beanId);
            if(!$bean){
                return false;
            }

            if(!self::isModuleSearchable($module,$bean->getObjectName())){
                return false;
            }

            $indexEvent = $this->getIndexEvent($module,$beanId);
            $indexEvent->name = $bean->get_summary_text();

            $document = $this->getDocumentForBean($bean);
            //Index name, id, date, filename
            if(!$document['error']){
                $this->remove($module,$beanId);
                $this->getLuceneIndex()->addDocument($document['document']);
                $indexEvent->success = true;
            }else{
                $indexEvent->success = false;
                $indexEvent->error = $document['error'];
            }
            $indexEvent->save();
        }catch(Exception $ex){
            $GLOBALS['log']->error($ex->getMessage());
            return false;
        }
    }
    private function getIdForDoc($module, $beanId){
        return $module . " " . $beanId;
    }

    private function remove($module, $beanId){
        $idTerm = new Zend_Search_Lucene_Index_Term($this->getIdForDoc($module,$beanId),"aod_id");
        $query = new Zend_Search_Lucene_Search_Query_Term($idTerm);
        $hits = $this->getLuceneIndex()->find($query);
        foreach ($hits as $hit) {
            $this->getLuceneIndex()->delete($hit->id);
        }
    }

    /**
     * Returns a handle on the actual lucene index.
     * @return Zend_Search_Lucene_Interface
     */
    private function getLuceneIndex(){
        if(!empty($this->index)){
            return $this->index;
        }
        if(file_exists($this->location)){
            $this->index = new Zend_Search_Lucene($this->location);
        }else{
            $this->index = Zend_Search_Lucene::create($this->location);
        }
        $this->index->setMaxBufferedDocs(64);
        //$this->index->setMaxMergeDocs(50);
        Zend_Search_Lucene_Search_Query_Fuzzy::setDefaultPrefixLength(1);
        $this->index->setMergeFactor(5);
        return $this->index;
    }


    public function getIndexableModules(){
        $modules = array();
        $beanList = $GLOBALS['beanList'];
        ksort($beanList);
        foreach($beanList as $beanModule => $beanName){
            if(self::isModuleSearchable($beanModule,$beanName)){
                $modules[$beanModule] = $beanName;
            }
        }
        return $modules;
    }
}
?>