Reviving some old PR with API get, activate and disable modules (#35718)

* Reviving some old PR with API get, activate and disable modules

* expanding hurl test for setup wih some module tests

* return array, not object

* fix PHPStan on getmodules

* typecasting module functions to string

* instiating class DolibarrModule into an object so we can call functions on it

---------

Co-authored-by: Jon Bendtsen <xcodeauthor@jonb.dk>
This commit is contained in:
Jon Bendtsen
2025-10-14 19:33:40 +02:00
committed by GitHub
parent 1ad2d24a4b
commit 7fc9b253bf
2 changed files with 236 additions and 4 deletions

View File

@@ -32,6 +32,8 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/cstate.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/cregion.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/ccountry.class.php';
require_once DOL_DOCUMENT_ROOT.'/hrm/class/establishment.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
/**
* API class for dictionaries
@@ -2911,18 +2913,20 @@ class Setup extends DolibarrApi
return array('resultcode' => $resultcode, 'resultcomment' => $resultcomment, 'expectedchecksum' => $outexpectedchecksum, 'currentchecksum' => $outcurrentchecksum, 'out' => $out);
}
/**
* Get list of enabled modules
*
* @url GET /modules
*
* @return array<string,string> Array of modules
* @return array Data without useless information
* @phan-return array<string,string>
* @phpstan-return array<string,string>
*
* @throws RestException 403 Forbidden
*/
public function getModules()
{
dol_syslog("Setup::getModules is DEPRECATED, use /api/index.php/setup/modules/status", LOG_INFO);
global $conf;
if (!DolibarrApiAccess::$user->admin
@@ -2932,7 +2936,156 @@ class Setup extends DolibarrApi
sort($conf->modules);
//return $this->_cleanObjectDatas($conf->modules);
return $conf->modules;
}
/**
* Get list of modules with status and origin
*
* @url GET /modules/status/{origin}
*
* @param string $status "all", "active", "disabled"
* @param string $origin Origin of the module (all, core, external)
* @return array|mixed Data without useless information
*
* @throws RestException 403 Forbidden
*/
public function getModulesList($status = "active", $origin = 'all')
{
global $db;
$moduleObject = new DolibarrModules($this->db);
if (!DolibarrApiAccess::$user->admin
&& (!getDolGlobalString('API_LOGINS_ALLOWED_FOR_GET_MODULES') || DolibarrApiAccess::$user->login != getDolGlobalString('API_LOGINS_ALLOWED_FOR_GET_MODULES'))) {
throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_GET_MODULES');
}
$filename = array();
$modulesdir = dolGetModulesDirs();
foreach ($modulesdir as $dir) {
// Load modules attributes in arrays (name, numero, orders) from dir directory
//print $dir."\n<br>";
dol_syslog("Scan directory ".$dir." for module descriptor files (modXXX.class.php)");
$handle = @opendir($dir);
if (is_resource($handle)) {
while (($file = readdir($handle)) !== false) {
//print "$i ".$file."\n<br>";
if (is_readable($dir.$file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') {
$modName = substr($file, 0, dol_strlen($file) - 10);
include_once $dir.$file; // A class already exists in a different file will send a non catchable fatal error.
if (class_exists($modName)) {
$objMod = new $modName($db);
$moduleName = strtoupper(preg_replace('/^mod/i', '', get_class($objMod)));
$publisher = dol_escape_htmltag((string) $moduleObject->getPublisher());
$external = ((string) $moduleObject->isCoreOrExternalModule() == 'external');
$active = getDolGlobalString('MAIN_MODULE_'.$moduleName);
$version = $objMod->version;
if ($status != 'all') {
if ($status == 'active' && $active == "") {
continue;
} elseif ($status == 'disabled' && $active == 1) {
continue;
}
}
if ($origin != 'all') {
if ($origin == 'external' && !$external) {
continue;
} elseif ($origin == 'core' && $external) {
continue;
}
}
$filename[$moduleName] = array(
'modName' => $modName,
'origin' => $external ? 'external' : 'core',
'active' => $active,
'publisher' => $publisher,
'version' => $version
);
}
}
}
}
}
return $filename;
}
/**
* PUT enable module
*
* @url PUT /modules/{modulename}/enable
*
* @param string $modulename name of the module
* @return array|mixed Data without useless information
*
* @throws RestException 403 Forbidden
* @throws RestException 404 Not found
*/
public function enableModules($modulename)
{
return $this->_moduleOnOff($modulename, $state = true);
}
/**
* PUT enable module
*
* @url PUT /modules/{modulename}/disable
*
* @param string $modulename name of the module
* @return array|mixed Data without useless information
*
* @throws RestException 403 Forbidden
* @throws RestException 404 Not found
*/
public function disableModules($modulename)
{
return $this->_moduleOnOff($modulename, $state = false);
}
/**
* switch moduleOnOff
*
* @param string $modulename name of the module
* @param bool $state false means off, true means on
* @return array|mixed Data without useless information
*
* @throws RestException 403 Forbidden
* @throws RestException 404 Not found
*/
private function _moduleOnOff($modulename, $state = false)
{
global $db;
if (!DolibarrApiAccess::$user->admin
&& (!getDolGlobalString('API_LOGINS_ALLOWED_FOR_GET_MODULES') || DolibarrApiAccess::$user->login != getDolGlobalString('API_LOGINS_ALLOWED_FOR_GET_MODULES'))) {
throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_GET_MODULES');
}
$modulesdir = dolGetModulesDirs();
foreach ($modulesdir as $dir) {
$handle = @opendir($dir);
if (is_resource($handle)) {
while (($file = readdir($handle)) !== false) {
if (is_readable($dir.$file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') {
// print $modulename. "==".substr($file, 0, dol_strlen($file) - 10)."\n";
if ($modulename == substr($file, 0, dol_strlen($file) - 10)) {
$modName = substr($file, 0, dol_strlen($file) - 10);
include_once $dir.$file; // A class already exists in a different file will send a non catchable fatal error.
if (class_exists($modName)) {
$objMod = new $modName($db);
//$name = strtoupper(preg_replace('/^mod/i', '', get_class($objMod)));
if ($state) {
activateModule($modulename);
return array('result' => 'success', 'message' => 'Module '.$this->db->escape($modulename).' activated');
} else {
unActivateModule($modulename);
return array('result' => 'success', 'message' => 'Module '.$this->db->escape($modulename).' deactivated');
}
}
}
}
}
}
}
throw new RestException(404, 'Module '.$this->db->escape($modulename).' not found');
}
}