1<?php 2/* Copyright (C) 2005-2009 Laurent Destailleur <eldy@users.sourceforge.net> 3 * Copyright (C) 2007 Rodolphe Quiedeville <rodolphe@quiedeville.org> 4 * Copyright (C) 2010-2012 Regis Houssin <regis.houssin@inodbox.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <https://www.gnu.org/licenses/>. 18 */ 19 20/** 21 * \file htdocs/admin/system/modules.php 22 * \brief File to list all Dolibarr modules 23 */ 24 25require '../../main.inc.php'; 26require_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php'; 27 28if (empty($user->admin)) { 29 accessforbidden(); 30} 31 32// Load translation files required by the page 33$langs->loadLangs(array("install", "other", "admin")); 34 35$optioncss = GETPOST('optioncss', 'alpha'); 36$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'moduleoverview'; 37 38$search_name = GETPOST("search_name", 'alpha'); 39$search_id = GETPOST("search_id", 'alpha'); 40$search_version = GETPOST("search_version", 'alpha'); 41$search_permission = GETPOST("search_permission", 'alpha'); 42 43$sortfield = GETPOST("sortfield", 'alpha'); 44$sortorder = GETPOST("sortorder", 'alpha'); 45 46if (!$sortfield) { 47 $sortfield = "id"; 48} 49if (!$sortorder) { 50 $sortorder = "asc"; 51} 52 53// Initialize technical object to manage hooks. Note that conf->hooks_modules contains array of hooks 54$hookmanager->initHooks(array('moduleoverview')); 55$form = new Form($db); 56$object = new stdClass(); 57 58// Definition of fields for lists 59$arrayfields = array( 60 'name'=>array('label'=>$langs->trans("Modules"), 'checked'=>1, 'position'=>10), 61 'version'=>array('label'=>$langs->trans("Version"), 'checked'=>1, 'position'=>20), 62 'id'=>array('label'=>$langs->trans("IdModule"), 'checked'=>1, 'position'=>30), 63 'module_position'=>array('label'=>$langs->trans("Position"), 'checked'=>1, 'position'=>35), 64 'permission'=>array('label'=>$langs->trans("IdPermissions"), 'checked'=>1, 'position'=>40) 65); 66 67$arrayfields = dol_sort_array($arrayfields, 'position'); 68$param = ''; 69 70 71/* 72 * Actions 73 */ 74 75$parameters = array(); 76$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks 77if ($reshook < 0) { 78 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); 79} 80 81if (empty($reshook)) { 82 // Selection of new fields 83 include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; 84} 85 86 87// Load list of modules 88$moduleList = array(); 89$modules = array(); 90$modules_files = array(); 91$modules_fullpath = array(); 92$modulesdir = dolGetModulesDirs(); 93$rights_ids = array(); 94 95foreach ($modulesdir as $dir) { 96 $handle = @opendir(dol_osencode($dir)); 97 if (is_resource($handle)) { 98 while (($file = readdir($handle)) !== false) { 99 if (is_readable($dir.$file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') { 100 $modName = substr($file, 0, dol_strlen($file) - 10); 101 102 if ($modName) { 103 //print 'xx'.$dir.$file.'<br>'; 104 if (in_array($file, $modules_files)) { 105 // File duplicate 106 print "Warning duplicate file found : ".$file." (Found ".$dir.$file.", already found ".$modules_fullpath[$file].")<br>"; 107 } else { 108 // File to load 109 $res = include_once $dir.$file; 110 if (class_exists($modName)) { 111 try { 112 $objMod = new $modName($db); 113 114 $modules[$objMod->numero] = $objMod; 115 $modules_files[$objMod->numero] = $file; 116 $modules_fullpath[$file] = $dir.$file; 117 } catch (Exception $e) { 118 dol_syslog("Failed to load ".$dir.$file." ".$e->getMessage(), LOG_ERR); 119 } 120 } else { 121 print "Warning bad descriptor file : ".$dir.$file." (Class ".$modName." not found into file)<br>"; 122 } 123 } 124 } 125 } 126 } 127 closedir($handle); 128 } 129} 130 131// create pre-filtered list for modules 132foreach ($modules as $key => $module) { 133 $newModule = new stdClass(); 134 135 $newModule->name = $module->getName(); 136 $newModule->version = $module->getVersion(); 137 $newModule->id = $key; 138 $newModule->module_position = $module->getModulePosition(); 139 140 $alt = $module->name.' - '.$modules_files[$key]; 141 142 if (!empty($module->picto)) { 143 if (preg_match('/^\//', $module->picto)) { 144 $newModule->picto = img_picto($alt, $module->picto, 'width="14px"', 1); 145 } else { 146 $newModule->picto = img_object($alt, $module->picto, 'width="14px"'); 147 } 148 } else { 149 $newModule->picto = img_object($alt, 'generic', 'width="14px"'); 150 } 151 152 $permission = array(); 153 if ($module->rights) { 154 foreach ($module->rights as $rights) { 155 if (empty($rights[0])) { 156 continue; 157 } 158 159 $permission[] = $rights[0]; 160 161 array_push($rights_ids, $rights[0]); 162 } 163 } 164 165 $newModule->permission = $permission; 166 167 // pre-filter list 168 if (!empty($search_name) && !stristr($newModule->name, $search_name)) { 169 continue; 170 } 171 if (!empty($search_version) && !stristr($newModule->version, $search_version)) { 172 continue; 173 } 174 if (!empty($search_id) && !stristr($newModule->id, $search_id)) { 175 continue; 176 } 177 178 if (!empty($search_permission)) { 179 $found = false; 180 181 foreach ($newModule->permission as $permission) { 182 if (stristr($permission, $search_permission)) { 183 $found = true; 184 break; 185 } 186 } 187 188 if (!$found) { 189 continue; 190 } 191 } 192 193 $moduleList[] = $newModule; 194} 195 196 197 198/* 199 * View 200 */ 201 202llxHeader(); 203 204print '<form action="'.$_SERVER["PHP_SELF"].'" method="post" name="formulaire">'; 205if ($optioncss != '') { 206 print '<input type="hidden" name="optioncss" value="'.$optioncss.'">'; 207} 208print '<input type="hidden" name="token" value="'.newToken().'">'; 209print '<input type="hidden" name="formfilteraction" id="formfilteraction" value="list">'; 210print '<input type="hidden" name="action" value="list">'; 211print '<input type="hidden" name="sortfield" value="'.$sortfield.'">'; 212print '<input type="hidden" name="sortorder" value="'.$sortorder.'">'; 213print '<input type="hidden" name="contextpage" value="'.$contextpage.'">'; 214 215print_barre_liste($langs->trans("AvailableModules"), empty($page) ? 0 : $page, $_SERVER["PHP_SELF"], '', $sortfield, $sortorder, '', -1, '', 'title_setup', 0, '', '', 0, 1, 1); 216 217print '<span class="opacitymedium">'.$langs->trans("ToActivateModule").'</span>'; 218print '<br>'; 219print '<br>'; 220 221$varpage = empty($contextpage) ? $_SERVER["PHP_SELF"] : $contextpage; 222$selectedfields = $form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields 223 224print '<div class="div-table-responsive-no-min">'; 225print '<table class="noborder centpercent">'; 226 227// Lines with input filters 228print '<tr class="liste_titre_filter">'; 229 230if ($arrayfields['name']['checked']) { 231 print '<td class="liste_titre left">'; 232 print '<input class="flat" type="text" name="search_name" size="8" value="'.dol_escape_htmltag($search_name).'">'; 233 print '</td>'; 234} 235if ($arrayfields['version']['checked']) { 236 print '<td class="liste_titre left">'; 237 print '<input class="flat" type="text" name="search_version" size="6" value="'.dol_escape_htmltag($search_version).'">'; 238 print '</td>'; 239} 240if ($arrayfields['id']['checked']) { 241 print '<td class="liste_titre left">'; 242 print '<input class="flat" type="text" name="search_id" size="6 value="'.dol_escape_htmltag($search_id).'">'; 243 print '</td>'; 244} 245if ($arrayfields['permission']['checked']) { 246 print '<td class="liste_titre left">'; 247 print '<input class="flat" type="text" name="search_permission" size="8" value="'.dol_escape_htmltag($search_permission).'">'; 248 print '</td>'; 249} 250if ($arrayfields['module_position']['checked']) { 251 print '<td class="liste_titre left">'; 252 print '</td>'; 253} 254 255print '<td class="liste_titre center maxwidthsearch">'; 256$searchpicto = $form->showFilterButtons(); 257print $searchpicto; 258print '</td>'; 259 260print '</tr>'; 261 262print '<tr class="liste_titre">'; 263 264if ($arrayfields['name']['checked']) { 265 print_liste_field_titre($arrayfields['name']['label'], $_SERVER["PHP_SELF"], "name", "", "", "", $sortfield, $sortorder); 266} 267if ($arrayfields['version']['checked']) { 268 print_liste_field_titre($arrayfields['version']['label'], $_SERVER["PHP_SELF"], "version", "", "", "", $sortfield, $sortorder); 269} 270if ($arrayfields['id']['checked']) { 271 print_liste_field_titre($arrayfields['id']['label'], $_SERVER["PHP_SELF"], "id", "", "", "", $sortfield, $sortorder, 'nowraponall '); 272} 273if ($arrayfields['permission']['checked']) { 274 print_liste_field_titre($arrayfields['permission']['label'], $_SERVER["PHP_SELF"], "permission", "", "", "", $sortfield, $sortorder); 275} 276if ($arrayfields['module_position']['checked']) { 277 print_liste_field_titre($arrayfields['module_position']['label'], $_SERVER["PHP_SELF"], "module_position", "", "", "", $sortfield, $sortorder); 278} 279 280// Fields from hook 281$parameters = array('arrayfields'=>$arrayfields, 'param'=>$param, 'sortfield'=>$sortfield, 'sortorder'=>$sortorder); 282$reshook = $hookmanager->executeHooks('printFieldListOption', $parameters); // Note that $action and $object may have been modified by hook 283print $hookmanager->resPrint; 284 285print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); 286print '</tr>'; 287 288// sort list 289if ($sortfield == "name" && $sortorder == "asc") { 290 usort($moduleList, function (stdClass $a, stdClass $b) { 291 return strcasecmp($a->name, $b->name); 292 }); 293} elseif ($sortfield == "name" && $sortorder == "desc") { 294 usort($moduleList, function (stdClass $a, stdClass $b) { 295 return strcasecmp($b->name, $a->name); 296 }); 297} elseif ($sortfield == "version" && $sortorder == "asc") { 298 usort($moduleList, function (stdClass $a, stdClass $b) { 299 return strcasecmp($a->version, $b->version); 300 }); 301} elseif ($sortfield == "version" && $sortorder == "desc") { 302 usort($moduleList, function (stdClass $a, stdClass $b) { 303 return strcasecmp($b->version, $a->version); 304 }); 305} elseif ($sortfield == "id" && $sortorder == "asc") { 306 usort($moduleList, "compareIdAsc"); 307} elseif ($sortfield == "id" && $sortorder == "desc") { 308 usort($moduleList, "compareIdDesc"); 309} elseif ($sortfield == "permission" && $sortorder == "asc") { 310 usort($moduleList, "comparePermissionIdsAsc"); 311} elseif ($sortfield == "permission" && $sortorder == "desc") { 312 usort($moduleList, "comparePermissionIdsDesc"); 313} else { 314 $moduleList = dol_sort_array($moduleList, 'module_position'); 315} 316 317foreach ($moduleList as $module) { 318 print '<tr class="oddeven">'; 319 320 if ($arrayfields['name']['checked']) { 321 print '<td width="300" class="nowrap">'; 322 print $module->picto; 323 print ' '.$module->name; 324 print "</td>"; 325 } 326 327 if ($arrayfields['version']['checked']) { 328 print '<td class="nowraponall">'.$module->version.'</td>'; 329 } 330 331 if ($arrayfields['id']['checked']) { 332 print '<td class="center">'.$module->id.'</td>'; 333 } 334 335 if ($arrayfields['permission']['checked']) { 336 $idperms = ''; 337 338 foreach ($module->permission as $permission) { 339 $idperms .= ($idperms ? ", " : "").$permission; 340 $translationKey = "Permission".$permission; 341 342 if (!empty($conf->global->MAIN_SHOW_PERMISSION)) { 343 if (empty($langs->tab_translate[$translationKey])) { 344 $tooltip = 'Missing translation (key '.$translationkey.' not found in admin.lang)'; 345 $idperms .= ' <img src="../../theme/eldy/img/warning.png" alt="Warning" title="'.$tooltip.'">'; 346 } 347 } 348 } 349 350 print '<td><span class="opacitymedium">'.($idperms ? $idperms : " ").'</span></td>'; 351 } 352 353 if ($arrayfields['module_position']['checked']) { 354 print '<td class="center">'.$module->module_position.'</td>'; 355 } 356 357 print '<td></td>'; 358 print '</tr>'; 359} 360 361print '</table>'; 362print '</div>'; 363print '</form>'; 364print '<br>'; 365 366sort($rights_ids); 367$old = ''; 368 369foreach ($rights_ids as $right_id) { 370 if ($old == $right_id) { 371 print "Warning duplicate id on permission : ".$right_id."<br>"; 372 } 373 374 $old = $right_id; 375} 376 377// End of page 378llxFooter(); 379$db->close(); 380 381 382 /** 383 * Compare two modules by their ID for a ascending order 384 * 385 * @param stdClass $a First module 386 * @param stdClass $b Second module 387 * @return int Compare result (-1, 0, 1) 388 */ 389function compareIdAsc(stdClass $a, stdClass $b) 390{ 391 if ((int) $a->id == (int) $b->id) { 392 return 0; 393 } 394 395 return ((int) $a->id < (int) $b->id) ? -1 : 1; 396} 397 398 /** 399 * Compare two modules by their ID for a descending order 400 * 401 * @param stdClass $a First module 402 * @param stdClass $b Second module 403 * @return int Compare result (-1, 0, 1) 404 */ 405function compareIdDesc(stdClass $a, stdClass $b) 406{ 407 if ((int) $a->id == (int) $b->id) { 408 return 0; 409 } 410 411 return ((int) $b->id < (int) $a->id) ? -1 : 1; 412} 413 414 /** 415 * Compare two modules by their ID for a ascending order 416 * 417 * @param stdClass $a First module 418 * @param stdClass $b Second module 419 * @return int Compare result (-1, 0, 1) 420 */ 421function comparePermissionIdsAsc(stdClass $a, stdClass $b) 422{ 423 if (empty($a->permission) && empty($b->permission)) { 424 return compareIdAsc($a, $b); 425 } 426 427 if (empty($a->permission)) { 428 return 1; 429 } 430 if (empty($b->permission)) { 431 return -1; 432 } 433 434 if ($a->permission[0] == $b->permission[0]) { 435 return 0; 436 } 437 438 return $a->permission[0] < $b->permission[0] ? -1 : 1; 439} 440 441 /** 442 * Compare two modules by their permissions for a descending order 443 * 444 * @param stdClass $a First module 445 * @param stdClass $b Second module 446 * @return int Compare result (-1, 0, 1) 447 */ 448function comparePermissionIdsDesc(stdClass $a, stdClass $b) 449{ 450 if (empty($a->permission) && empty($b->permission)) { 451 return compareIdDesc($a, $b); 452 } 453 454 if (empty($a->permission)) { 455 return -1; 456 } 457 if (empty($b->permission)) { 458 return 1; 459 } 460 461 if ($a->permission[0] == $b->permission[0]) { 462 return 0; 463 } 464 465 return $b->permission[0] < $a->permission[0] ? -1 : 1; 466} 467