altocompta/include/class/extension.class.php

469 lines
16 KiB
PHP

<?php
/*
* This file is part of NOALYSS.
*
* NOALYSS is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* NOALYSS 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with NOALYSS; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Copyright Author Dany De Bontridder danydb@aevalys.eu
/*!\file
* \brief the extension class manages the plugins for the security, the access
* the inclusion...
*/
/*!
*
* \class Extension
*
* \brief manage the extension, it involves the table extension
*
* Data member
* - $cn database connection
* - $variable :
* - id (extension.ex_id)
* - name (extension.ex_name)
* - plugin_code (extension.ex_code)
* - desc (extension.ex_desc)
* - enable (extension.ex_enable)
* - filepath (extension.ex_file)
*/
require_once NOALYSS_INCLUDE.'/database/menu_ref_sql.class.php';
require_once NOALYSS_INCLUDE.'/database/profile_sql.class.php';
class Extension extends Menu_Ref_sql
{
// code of the standard plugin (from noalyss-plugins)
const aStandard_plugin=
array('AMORTIS','BACKNOADM','COPRO','IMPCARD',
'IMPORTBANK','INVOICING','LISTING',
'MODOP','RAPAV','SAV',
'TOOLPCMN','TOOLS','TRANSFORM',
'TVA');
/**************************************************************************
* Variables from plugin.xml
*************************************************************************/
var $version; //<! version of the plugin in the XML
var $noalyss_version; //!< minimum version of NOALYSS for this plugin
var $order ; //!< $order in the menu (can be override by config menu)
var $depend; //!< default depending menu (can be override by config menu)
public function verify()
{
// Verify that the elt we want to add is correct
if (trim($this->me_code)=="")
throw new Exception('Le code ne peut pas être vide');
if (trim($this->me_menu)=="")
throw new Exception('Le nom ne peut pas être vide');
if (trim($this->me_file)=="")
throw new Exception('Chemin incorrect');
if (file_exists(NOALYSS_PLUGIN.'/'.$this->me_file)==false)
throw new Exception("$this->me_code $this->me_file".'Extension non trouvée, le chemin est-il correct?');
}
/*!@brief search a extension, the what is the column (extends_code */
function search($p_what)
{
$this->me_code=strtoupper($p_what);
if ($this->load()==false)
return null;
return 1;
}
/*!\brief return 1 if the user given in parameter can access this extension
* otherwise returns 0
* \param $p_login the user login
* \return 1 has access, 0 has no access
*/
function can_request($p_login)
{
$cnt=$this->cn->get_value("select count(*) from menu_ref
join profile_menu using (me_code)
join profile_user using (p_id)
where
me_code=$1
and user_name=$2", array($this->me_code, $p_login));
if ($cnt>0)
return 1;
return 0;
}
/*!@brief make an array of the available plugin for the current user
* @return an array
* @see ISelect
*/
static function make_array($cn)
{
$sql="select DISTINCT me_code as value, me_menu as label from ".
" menu_ref join profile_menu using (me_code)
join profile_user using (p_id) where ".
" user_name=$1 and me_type='PL' ORDER BY ME_MENU";
$a=$cn->get_array($sql, array($_SESSION[SESSION_KEY.'g_user']));
return $a;
}
/**
* @brief check the version of the plugin , null stands for one of the standard plugins, it means
* self::aStandard_plugin
* @global type $version_noalyss
* @param type $i
* @param type $p_plugin_code
* @return type
*/
static function check_version($i,$p_plugin_code=null)
{
global $version_noalyss;
if (!isset($version_noalyss)||$version_noalyss<$i)
{
alert(_('Cette extension ne fonctionne pas sur cette version de NOALYSS'.
' Veuillez mettre votre programme a jour. Version minimum ').$i);
return;
}
Extension::check_plugin_version($p_plugin_code);
}
/**
* @brief insert into the table profile_menu for the given profile id and depending
* of the module $p_module
* @remark type $cn
* @param type $p_id profile.p_id
* @throws Exception 10 : profile absent , 20 module absent , 30 No parent menu
*/
function insert_profile_menu($p_id=1)
{
global $cn;
// Module for the plugin
$p_module=$this->depend;
//profile exists ?
$profile=new Profile_sql($cn, $p_id);
if ($profile->p_id!=$p_id)
{
throw new Exception(_('Profil inexistant'), 10);
}
// Menu exists
$module=new Menu_Ref($cn, $p_module);
if ($module->me_code==null)
{
throw new Exception(_('Module inexistant'), 20);
}
// Dependency
$dep_id=$cn->get_array('select pm_id from profile_menu
where
p_id=$1
and me_code = $2 ', array($p_id, $p_module));
// throw an exception if there is no dependency
if (empty($dep_id))
{
$msg = sprintf(_("Le menu %s dont dépend %s doit être crée ou %s doit être ajouté depuis le menu C0PROFL"),
$p_module,$this->me_code,$this->me_code);
throw new Exception($msg, 30);
}
$nb_dep=count($dep_id);
// insert at the right location
for ($i=0; $i<$nb_dep; $i++)
{
$profil_menu=new Profile_Menu($cn);
$profil_menu->me_code=$this->me_code;
$profil_menu->me_code_dep=$p_module;
$profil_menu->p_type_display='S';
$profil_menu->p_id=$p_id;
$profil_menu->pm_id_dep=$dep_id[$i]['pm_id'];
$profil_menu->pm_default=0;
$profil_menu->p_order=$this->order;
$cnt=$profil_menu->count(' where pm_id_dep=$3 and p_id=$1 and me_code = $2',
array($p_id, $this->me_code, $dep_id[$i]['pm_id']));
if ($cnt==0)
{
$profil_menu->insert();
}
}
}
function remove_from_profile_menu($p_id)
{
global $cn;
$cn->exec_sql('delete from profile_menu where (me_code = $1 or me_code in (select me_code from menu_ref where me_file=$2)) and p_id=$3',
array($this->me_code, $this->me_file, $p_id));
}
/**
* @brief save a plugin into MENU_REF , calls insert_plugin or update_plugin if it already exists
* @return void
*/
function save_plugin()
{
if ( $this->cn->get_value("select count(*) from menu_ref where me_code=$1",[$this->me_code]) > 0) {
$this->update_plugin();
} else {
$this->insert_plugin();
}
}
/**
* @brief Insert a plugin into the given profile, by default always insert into EXT
*
* @param type $p_id profile.p_id
* @throws Exception if duplicate or error db
*/
function insert_plugin()
{
try
{
$this->cn->start();
$this->verify();
// check if duplicate
$this->me_code=strtoupper($this->me_code);
$count=$this->cn->get_value("select count(*) from menu_ref where me_code=$1", array($this->me_code));
if ($count!=0)
throw new Exception("Doublon");
$this->me_type='PL';
$this->insert();
$this->cn->commit();
}
catch (Exception $exc)
{
echo alert($exc->getMessage());
}
}
function update_plugin()
{
try
{
$this->cn->start();
$this->verify();
$this->me_type='PL';
$this->update();
$this->cn->commit();
}
catch (Exception $exc)
{
echo alert($exc->getMessage());
}
}
function remove_plugin()
{
try
{
$this->cn->start();
$this->delete();
$this->cn->commit();
}
catch (Exception $exc)
{
echo alert($exc->getMessage());
}
}
/**
* @brief remove all the standard plugins schema
* @param Database $p_cn
*/
static function clean(Database $p_cn)
{
$a_ext=array("tva_belge", "amortissement", "impdol", "coprop", "importbank");
for ($i=0; $i<count($a_ext); $i++)
{
if ($p_cn->exist_schema($a_ext[$i]))
{
$p_cn->exec_sql("drop schema ".$a_ext[$i]." cascade");
}
}
}
/**
* @brief compare the version of the plugin and the last version , propose to update it if a new version exists
* @todo add a mechanism to check once a day
* @global User $g_user
* @global number $version_plugin
*/
static function check_plugin_version($p_plugin_code)
{
global $g_user, $version_plugin;
if ($g_user->Admin()==1)
{
if ( in_array($p_plugin_code, self::aStandard_plugin) && SITE_UPDATE_PLUGIN!="")
{
$update=@file_get_contents(SITE_UPDATE_PLUGIN);
if ($update>$version_plugin)
{
echo '<div id="version_plugin_div_id" class="inner_box" style="position:absolute;zindex:2;top:5px;left:37.5%;width:25%">';
echo '<p class="notice">';
echo "Mise à jour disponible des plugins pour NOALYSS, version actuelle : $update votre version $version_plugin";
echo '</p>';
echo '<p style="text-align:center">'.
'<a id="version_plugin_button" class="button" onclick="$(\'version_plugin_div_id\').remove()">'.
_('Fermer').
"</a></p>";
echo '</div>';
}
}
}
}
/**
* Check that the xml contains all the needed information to change them into
* a extension, the exception code is 0 if the element is optional
* @brief Check XML.
* @param SimpleXMLElement $xml
* @throws Exception
*/
function check_xml(SimpleXMLElement $xml)
{
try
{
if (!isset($xml->plugin))
throw new Exception(_('Manque plugin'), 1);
$nb_plugin=count($xml->plugin);
for ($i=0; $i<$nb_plugin; $i++)
{
if (!isset($xml->plugin[$i]->name))
throw new Exception(_('Manque nom'), 1);
if (!isset($xml->plugin[$i]->description))
throw new Exception(_('Manque description'), 0);
if (!isset($xml->plugin[$i]->code))
throw new Exception(_('Manque code'), 1);
if (!isset($xml->plugin[$i]->author))
throw new Exception(_('Manque auteur'), 0);
if (!isset($xml->plugin[$i]->root))
throw new Exception(_('Manque répertoire racine'), 1);
if (!isset($xml->plugin[$i]->file))
throw new Exception(_('Manque fichier à inclure'), 1);
if (!isset($xml->plugin[$i]->version))
throw new Exception(_("Manque version de l'extension"), 1);
if (!isset($xml->plugin[$i]->depend))
$xml->plugin[$i]->depend="EXT";
if (!isset($xml->plugin[$i]->order))
$xml->plugin[$i]->order=9000;
}
}
catch (Exception $ex)
{
throw $ex;
}
}
/**
* @brief Parse a XML file to complete an array of extension objects, in the plugin.xml file , you can find
* several plugins sharing some parts.
*
* @param string $p_file filename
* @return array array of Extension
*/
static function read_definition($p_file)
{
global $cn;
$dom=new DomDocument('1.0');
$dom->load($p_file);
$xml=simplexml_import_dom($dom);
$nb_plugin=count($xml->plugin);
$a_extension=array();
for ($i=0; $i<$nb_plugin; $i++)
{
$extension=new Extension($cn);
try
{
$extension->check_xml($xml);
}
catch (Exception $ex)
{
echo_warning($ex->getMessage());
if ($ex->getCode()==1)
{
continue;
}
}
$extension->me_file=trim($xml->plugin[$i]->root).'/'.trim($xml->plugin[$i]->file);
$extension->me_code=trim($xml->plugin[$i]->code);
$extension->me_description=(isset($xml->plugin[$i]->description))?trim($xml->plugin[$i]->description):"";
$extension->me_description_etendue=(trim($xml->plugin[$i]->author))?trim($xml->plugin[$i]->author):"";
$extension->me_type='PL';
$extension->me_menu=trim($xml->plugin[$i]->name);
$extension->me_parameter='plugin_code='.trim($xml->plugin[$i]->code);
$extension->depend=(isset($xml->plugin[$i]->depend))?trim($xml->plugin[$i]->depend):"EXT";
$extension->order=(isset($xml->plugin[$i]->order))?trim($xml->plugin[$i]->order):9000;
$extension->version=trim($xml->plugin[$i]->version);
$extension->noalyss_version=(isset($xml->plugin[$i]->noalyss_version))?trim($xml->plugin[$i]->noalyss_version):8000;
$a_extension[]=clone $extension;
}
return $a_extension;
}
/**
* @brief find the extension with the me_code = last part of access_code
* @param $a_extension
* @param $access_code find the ME_CODE (normally last part )
* @return the extension or null
*/
public static function find_extension_code($a_extension,$access_code):Extension|null
{
$a_me_code=explode("/", $access_code);
if (empty($a_me_code ) ) return null;
$nb_me_code=count($a_me_code);
$me_code=$a_me_code[$nb_me_code-1];
foreach ($a_extension as $extension) {
if ($extension->me_code==$me_code) return $extension;
}
return null;
}
public function __toString(): string
{
$r = "";
$r .= " me_code " . $this->me_code.PHP_EOL;
$r .= " me_menu.".$this->me_menu.PHP_EOL;
$r .= " version".$this->version.PHP_EOL;
$r .= " noalyss_version".$this->noalyss_version.PHP_EOL;
$r .= " me_file" . $this->me_file.PHP_EOL;
$r .= " me_url" . $this->me_url.PHP_EOL;
$r .= " me_description" . $this->me_description.PHP_EOL;
$r .= " me_parameter" . $this->me_parameter.PHP_EOL;
$r .= " me_javascript" . $this->me_javascript.PHP_EOL;
$r .= " me_type" . $this->me_type.PHP_EOL;
$r .= " me_descrition_etendue" . $this->me_description_etendue.PHP_EOL;
$r .= " noalyss_version " . $this->noalyss_version.PHP_EOL;
$r .= " version " . $this->version.PHP_EOL;
$r .= " order " . $this->order.PHP_EOL;
$r .= " depend " . $this->depend.PHP_EOL;
return "Extension $r";
}
/**
* @brief retrieve the version of the current plugin
* @param $xml_file always __DIR__."/plugin.xml"
* @param $plugin_code the plugin or $_REQUEST['ac']
* @return int version or -1 if not found
*/
public static function get_version($xml_file,$plugin_code):int
{
$aExtension=\Extension::read_definition($xml_file);
$extension=self::find_extension_code($aExtension, $plugin_code);
if ( empty($plugin_code)) return -1;
return $extension->version??0;
}
}