1 | <?php |
||||
2 | |||||
3 | /* Copyright (C) 2003-2007 Rodolphe Quiedeville <[email protected]> |
||||
4 | * Copyright (C) 2003 Jean-Louis Bergamo <[email protected]> |
||||
5 | * Copyright (C) 2004-2017 Laurent Destailleur <[email protected]> |
||||
6 | * Copyright (C) 2004 Eric Seigne <[email protected]> |
||||
7 | * Copyright (C) 2005-2017 Regis Houssin <[email protected]> |
||||
8 | * Copyright (C) 2011-2023 Juanjo Menent <[email protected]> |
||||
9 | * Copyright (C) 2015 Jean-François Ferry <[email protected]> |
||||
10 | * Copyright (C) 2015 Raphaël Doursenaud <[email protected]> |
||||
11 | * Copyright (C) 2018 Nicolas ZABOURI <[email protected]> |
||||
12 | * Copyright (C) 2021-2023 Frédéric France <[email protected]> |
||||
13 | * Copyright (C) 2024 MDW <[email protected]> |
||||
14 | * Copyright (C) 2024 Rafael San José <[email protected]> |
||||
15 | * |
||||
16 | * This program is free software; you can redistribute it and/or modify |
||||
17 | * it under the terms of the GNU General Public License as published by |
||||
18 | * the Free Software Foundation; either version 3 of the License, or |
||||
19 | * (at your option) any later version. |
||||
20 | * |
||||
21 | * This program is distributed in the hope that it will be useful, |
||||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
24 | * GNU General Public License for more details. |
||||
25 | * |
||||
26 | * You should have received a copy of the GNU General Public License |
||||
27 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||
28 | */ |
||||
29 | |||||
30 | use Dolibarr\Code\Core\Classes\Form; |
||||
31 | use Dolibarr\Core\Base\DolibarrModules; |
||||
32 | use Dolibarr\Lib\ViewMain; |
||||
33 | |||||
34 | /** |
||||
35 | * \file htdocs/admin/modules.php |
||||
36 | * \brief Page to activate/disable all modules |
||||
37 | */ |
||||
38 | |||||
39 | if (!defined('CSRFCHECK_WITH_TOKEN') && (empty($_GET['action']) || $_GET['action'] != 'reset')) { // We force security except to disable modules so we can do it if a problem occurs on a module |
||||
40 | define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET |
||||
41 | } |
||||
42 | |||||
43 | // Load Dolibarr environment |
||||
44 | require constant('DOL_DOCUMENT_ROOT') . '/main.inc.php'; |
||||
45 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/admin.lib.php'; |
||||
46 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php'; |
||||
47 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/geturl.lib.php'; |
||||
48 | require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/functions2.lib.php'; |
||||
49 | require_once constant('DOL_DOCUMENT_ROOT') . '/admin/dolistore/class/dolistore.class.php'; |
||||
50 | |||||
51 | // Load translation files required by the page |
||||
52 | $langs->loadLangs(array("errors", "admin", "modulebuilder")); |
||||
53 | |||||
54 | // if we set another view list mode, we keep it (till we change one more time) |
||||
55 | if (GETPOSTISSET('mode')) { |
||||
56 | $mode = GETPOST('mode', 'alpha'); |
||||
57 | if ($mode == 'common' || $mode == 'commonkanban') { |
||||
58 | dolibarr_set_const($db, "MAIN_MODULE_SETUP_ON_LIST_BY_DEFAULT", $mode, 'chaine', 0, '', $conf->entity); |
||||
59 | } |
||||
60 | } else { |
||||
61 | $mode = (!getDolGlobalString('MAIN_MODULE_SETUP_ON_LIST_BY_DEFAULT') ? 'commonkanban' : $conf->global->MAIN_MODULE_SETUP_ON_LIST_BY_DEFAULT); |
||||
62 | } |
||||
63 | |||||
64 | $action = GETPOST('action', 'aZ09'); |
||||
65 | $value = GETPOST('value', 'alpha'); |
||||
66 | $page_y = GETPOSTINT('page_y'); |
||||
67 | $search_keyword = GETPOST('search_keyword', 'alpha'); |
||||
68 | $search_status = GETPOST('search_status', 'alpha'); |
||||
69 | $search_nature = GETPOST('search_nature', 'alpha'); |
||||
70 | $search_version = GETPOST('search_version', 'alpha'); |
||||
71 | |||||
72 | |||||
73 | // For dolistore search |
||||
74 | $options = array(); |
||||
75 | $options['per_page'] = 20; |
||||
76 | $options['categorie'] = ((int)(GETPOSTINT('categorie') ? GETPOSTINT('categorie') : 0)); |
||||
77 | $options['start'] = ((int)(GETPOSTINT('start') ? GETPOSTINT('start') : 0)); |
||||
78 | $options['end'] = ((int)(GETPOSTINT('end') ? GETPOSTINT('end') : 0)); |
||||
79 | $options['search'] = GETPOST('search_keyword', 'alpha'); |
||||
80 | $dolistore = new Dolistore(false); |
||||
81 | |||||
82 | |||||
83 | if (!$user->admin) { |
||||
84 | accessforbidden(); |
||||
85 | } |
||||
86 | |||||
87 | $familyinfo = array( |
||||
88 | 'hr' => array('position' => '001', 'label' => $langs->trans("ModuleFamilyHr")), |
||||
89 | 'crm' => array('position' => '006', 'label' => $langs->trans("ModuleFamilyCrm")), |
||||
90 | 'srm' => array('position' => '007', 'label' => $langs->trans("ModuleFamilySrm")), |
||||
91 | 'financial' => array('position' => '009', 'label' => $langs->trans("ModuleFamilyFinancial")), |
||||
92 | 'products' => array('position' => '012', 'label' => $langs->trans("ModuleFamilyProducts")), |
||||
93 | 'projects' => array('position' => '015', 'label' => $langs->trans("ModuleFamilyProjects")), |
||||
94 | 'ecm' => array('position' => '018', 'label' => $langs->trans("ModuleFamilyECM")), |
||||
95 | 'technic' => array('position' => '021', 'label' => $langs->trans("ModuleFamilyTechnic")), |
||||
96 | 'portal' => array('position' => '040', 'label' => $langs->trans("ModuleFamilyPortal")), |
||||
97 | 'interface' => array('position' => '050', 'label' => $langs->trans("ModuleFamilyInterface")), |
||||
98 | 'base' => array('position' => '060', 'label' => $langs->trans("ModuleFamilyBase")), |
||||
99 | 'other' => array('position' => '100', 'label' => $langs->trans("ModuleFamilyOther")), |
||||
100 | ); |
||||
101 | |||||
102 | $param = ''; |
||||
103 | if (!GETPOST('buttonreset', 'alpha')) { |
||||
104 | if ($search_keyword) { |
||||
105 | $param .= '&search_keyword=' . urlencode($search_keyword); |
||||
106 | } |
||||
107 | if ($search_status && $search_status != '-1') { |
||||
108 | $param .= '&search_status=' . urlencode($search_status); |
||||
109 | } |
||||
110 | if ($search_nature && $search_nature != '-1') { |
||||
111 | $param .= '&search_nature=' . urlencode($search_nature); |
||||
112 | } |
||||
113 | if ($search_version && $search_version != '-1') { |
||||
114 | $param .= '&search_version=' . urlencode($search_version); |
||||
115 | } |
||||
116 | } |
||||
117 | |||||
118 | $dirins = DOL_DOCUMENT_ROOT . '/custom'; |
||||
119 | $urldolibarrmodules = 'https://www.dolistore.com/'; |
||||
120 | |||||
121 | // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context |
||||
122 | $hookmanager->initHooks(array('adminmodules', 'globaladmin')); |
||||
123 | |||||
124 | // Increase limit of time. Works only if we are not in safe mode |
||||
125 | $max_execution_time_for_deploy = getDolGlobalInt('MODULE_UPLOAD_MAX_EXECUTION_TIME', 300); // 5mn if not defined |
||||
126 | if (!empty($max_execution_time_for_deploy)) { |
||||
127 | $err = error_reporting(); |
||||
128 | error_reporting(0); // Disable all errors |
||||
129 | //error_reporting(E_ALL); |
||||
130 | @set_time_limit($max_execution_time_for_deploy); |
||||
0 ignored issues
–
show
|
|||||
131 | error_reporting($err); |
||||
132 | } |
||||
133 | // Other method - TODO is this required ? |
||||
134 | $max_time = @ini_get("max_execution_time"); |
||||
135 | if ($max_time && $max_time < $max_execution_time_for_deploy) { |
||||
136 | dol_syslog("max_execution_time=" . $max_time . " is lower than max_execution_time_for_deploy=" . $max_execution_time_for_deploy . ". We try to increase it dynamically."); |
||||
137 | @ini_set("max_execution_time", $max_execution_time_for_deploy); // This work only if safe mode is off. also web servers has timeout of 300 |
||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
ini_set() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||
138 | } |
||||
139 | |||||
140 | |||||
141 | $dolibarrdataroot = preg_replace('/([\\/]+)$/i', '', DOL_DATA_ROOT); |
||||
142 | $allowonlineinstall = true; |
||||
143 | $allowfromweb = 1; |
||||
144 | if (dol_is_file($dolibarrdataroot . '/installmodules.lock')) { |
||||
145 | $allowonlineinstall = false; |
||||
146 | } |
||||
147 | |||||
148 | |||||
149 | /* |
||||
150 | * Actions |
||||
151 | */ |
||||
152 | |||||
153 | $formconfirm = ''; |
||||
154 | |||||
155 | $parameters = array(); |
||||
156 | $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks |
||||
157 | if ($reshook < 0) { |
||||
158 | setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); |
||||
159 | } |
||||
160 | |||||
161 | if (GETPOST('buttonreset', 'alpha')) { |
||||
162 | $search_keyword = ''; |
||||
163 | $search_status = ''; |
||||
164 | $search_nature = ''; |
||||
165 | $search_version = ''; |
||||
166 | } |
||||
167 | |||||
168 | if ($action == 'install' && $allowonlineinstall) { |
||||
169 | $error = 0; |
||||
170 | |||||
171 | // $original_file should match format module_modulename-x.y[.z].zip |
||||
172 | $original_file = basename($_FILES["fileinstall"]["name"]); |
||||
173 | $original_file = preg_replace('/\s*\(\d+\)\.zip$/i', '.zip', $original_file); |
||||
174 | $newfile = $conf->admin->dir_temp . '/' . $original_file . '/' . $original_file; |
||||
175 | |||||
176 | if (!$original_file) { |
||||
177 | $langs->load("Error"); |
||||
178 | setEventMessages($langs->trans("ErrorModuleFileRequired"), null, 'warnings'); |
||||
179 | $error++; |
||||
180 | } else { |
||||
181 | if (!$error && !preg_match('/\.zip$/i', $original_file)) { |
||||
182 | $langs->load("errors"); |
||||
183 | setEventMessages($langs->trans("ErrorFileMustBeADolibarrPackage", $original_file), null, 'errors'); |
||||
184 | $error++; |
||||
185 | } |
||||
186 | if (!$error && !preg_match('/^(module[a-zA-Z0-9]*|theme)_.*\-([0-9][0-9\.]*)\.zip$/i', $original_file)) { |
||||
187 | $langs->load("errors"); |
||||
188 | setEventMessages($langs->trans("ErrorFilenameDosNotMatchDolibarrPackageRules", $original_file, 'module_*-x.y*.zip'), null, 'errors'); |
||||
189 | $error++; |
||||
190 | } |
||||
191 | if (empty($_FILES['fileinstall']['tmp_name'])) { |
||||
192 | $langs->load("errors"); |
||||
193 | setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors'); |
||||
194 | $error++; |
||||
195 | } |
||||
196 | } |
||||
197 | |||||
198 | if (!$error) { |
||||
199 | if ($original_file) { |
||||
200 | @dol_delete_dir_recursive($conf->admin->dir_temp . '/' . $original_file); |
||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
dol_delete_dir_recursive() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||
201 | dol_mkdir($conf->admin->dir_temp . '/' . $original_file); |
||||
202 | } |
||||
203 | |||||
204 | $tmpdir = preg_replace('/\.zip$/i', '', $original_file) . '.dir'; |
||||
205 | if ($tmpdir) { |
||||
206 | @dol_delete_dir_recursive($conf->admin->dir_temp . '/' . $tmpdir); |
||||
207 | dol_mkdir($conf->admin->dir_temp . '/' . $tmpdir); |
||||
208 | } |
||||
209 | |||||
210 | $result = dol_move_uploaded_file($_FILES['fileinstall']['tmp_name'], $newfile, 1, 0, $_FILES['fileinstall']['error']); |
||||
211 | if ($result > 0) { |
||||
212 | $result = dol_uncompress($newfile, $conf->admin->dir_temp . '/' . $tmpdir); |
||||
213 | |||||
214 | if (!empty($result['error'])) { |
||||
215 | $langs->load("errors"); |
||||
216 | setEventMessages($langs->trans($result['error'], $original_file), null, 'errors'); |
||||
217 | $error++; |
||||
218 | } else { |
||||
219 | // Now we move the dir of the module |
||||
220 | $modulename = preg_replace('/module_/', '', $original_file); |
||||
221 | $modulename = preg_replace('/\-([0-9][0-9\.]*)\.zip$/i', '', $modulename); |
||||
222 | // Search dir $modulename |
||||
223 | $modulenamedir = $conf->admin->dir_temp . '/' . $tmpdir . '/' . $modulename; // Example ./mymodule |
||||
224 | |||||
225 | if (!dol_is_dir($modulenamedir)) { |
||||
226 | $modulenamedir = $conf->admin->dir_temp . '/' . $tmpdir . '/htdocs/' . $modulename; // Example ./htdocs/mymodule |
||||
227 | //var_dump($modulenamedir); |
||||
228 | if (!dol_is_dir($modulenamedir)) { |
||||
229 | setEventMessages($langs->trans("ErrorModuleFileSeemsToHaveAWrongFormat") . '<br>' . $langs->trans("ErrorModuleFileSeemsToHaveAWrongFormat2", $modulename, 'htdocs/' . $modulename), null, 'errors'); |
||||
230 | $error++; |
||||
231 | } |
||||
232 | } |
||||
233 | |||||
234 | if (!$error) { |
||||
235 | // TODO Make more test |
||||
236 | } |
||||
237 | |||||
238 | dol_syslog("Uncompress of module file is a success."); |
||||
239 | |||||
240 | // We check if this is a metapackage |
||||
241 | $modulenamearrays = array(); |
||||
242 | if (dol_is_file($modulenamedir . '/metapackage.conf')) { |
||||
243 | // This is a meta package |
||||
244 | $metafile = file_get_contents($modulenamedir . '/metapackage.conf'); |
||||
245 | $modulenamearrays = explode("\n", $metafile); |
||||
246 | } |
||||
247 | $modulenamearrays[$modulename] = $modulename; |
||||
248 | //var_dump($modulenamearrays);exit; |
||||
249 | |||||
250 | // Lop on each package of the metapackage |
||||
251 | foreach ($modulenamearrays as $modulenameval) { |
||||
252 | if (strpos($modulenameval, '#') === 0) { |
||||
253 | continue; // Discard comments |
||||
254 | } |
||||
255 | if (strpos($modulenameval, '//') === 0) { |
||||
256 | continue; // Discard comments |
||||
257 | } |
||||
258 | if (!trim($modulenameval)) { |
||||
259 | continue; |
||||
260 | } |
||||
261 | |||||
262 | // Now we install the module |
||||
263 | if (!$error) { |
||||
264 | @dol_delete_dir_recursive($dirins . '/' . $modulenameval); // delete the target directory |
||||
265 | $submodulenamedir = $conf->admin->dir_temp . '/' . $tmpdir . '/' . $modulenameval; |
||||
266 | if (!dol_is_dir($submodulenamedir)) { |
||||
267 | $submodulenamedir = $conf->admin->dir_temp . '/' . $tmpdir . '/htdocs/' . $modulenameval; |
||||
268 | } |
||||
269 | dol_syslog("We copy now directory " . $submodulenamedir . " into target dir " . $dirins . '/' . $modulenameval); |
||||
270 | $result = dolCopyDir($submodulenamedir, $dirins . '/' . $modulenameval, '0444', 1); |
||||
271 | if ($result <= 0) { |
||||
272 | dol_syslog('Failed to call dolCopyDir result=' . $result . " with param " . $submodulenamedir . " and " . $dirins . '/' . $modulenameval, LOG_WARNING); |
||||
273 | $langs->load("errors"); |
||||
274 | setEventMessages($langs->trans("ErrorFailToCopyDir", $submodulenamedir, $dirins . '/' . $modulenameval), null, 'errors'); |
||||
275 | $error++; |
||||
276 | } |
||||
277 | } |
||||
278 | } |
||||
279 | } |
||||
280 | } else { |
||||
281 | setEventMessages($langs->trans("ErrorFailToRenameFile", $_FILES['fileinstall']['tmp_name'], $newfile), null, 'errors'); |
||||
282 | $error++; |
||||
283 | } |
||||
284 | } |
||||
285 | |||||
286 | if (!$error) { |
||||
287 | $message = $langs->trans("SetupIsReadyForUse", constant('BASE_URL') . '/admin/modules.php?mainmenu=home', $langs->transnoentitiesnoconv("Home") . ' - ' . $langs->transnoentitiesnoconv("Setup") . ' - ' . $langs->transnoentitiesnoconv("Modules")); |
||||
288 | setEventMessages($message, null, 'warnings'); |
||||
289 | } |
||||
290 | } elseif ($action == 'install' && !$allowonlineinstall) { |
||||
291 | httponly_accessforbidden("You try to bypass the protection to disallow deployment of an external module. Hack attempt ?"); |
||||
292 | } |
||||
293 | |||||
294 | if ($action == 'set' && $user->admin) { |
||||
295 | $checkOldValue = getDolGlobalInt('CHECKLASTVERSION_EXTERNALMODULE'); |
||||
296 | $csrfCheckOldValue = getDolGlobalInt('MAIN_SECURITY_CSRF_WITH_TOKEN'); |
||||
297 | $resarray = activateModule($value); |
||||
298 | if ($checkOldValue != getDolGlobalInt('CHECKLASTVERSION_EXTERNALMODULE')) { |
||||
299 | setEventMessage($langs->trans('WarningModuleHasChangedLastVersionCheckParameter', $value), 'warnings'); |
||||
300 | } |
||||
301 | if ($csrfCheckOldValue != getDolGlobalInt('MAIN_SECURITY_CSRF_WITH_TOKEN')) { |
||||
302 | setEventMessage($langs->trans('WarningModuleHasChangedSecurityCsrfParameter', $value), 'warnings'); |
||||
303 | } |
||||
304 | dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity); |
||||
305 | if (!empty($resarray['errors'])) { |
||||
306 | setEventMessages('', $resarray['errors'], 'errors'); |
||||
307 | } else { |
||||
308 | //var_dump($resarray);exit; |
||||
309 | if ($resarray['nbperms'] > 0) { |
||||
310 | $tmpsql = "SELECT COUNT(rowid) as nb FROM " . MAIN_DB_PREFIX . "user WHERE admin <> 1"; |
||||
311 | $resqltmp = $db->query($tmpsql); |
||||
312 | if ($resqltmp) { |
||||
313 | $obj = $db->fetch_object($resqltmp); |
||||
314 | //var_dump($obj->nb);exit; |
||||
315 | if ($obj && $obj->nb > 1) { |
||||
316 | $msg = $langs->trans('ModuleEnabledAdminMustCheckRights'); |
||||
317 | setEventMessages($msg, null, 'warnings'); |
||||
318 | } |
||||
319 | } else { |
||||
320 | dol_print_error($db); |
||||
321 | } |
||||
322 | } |
||||
323 | } |
||||
324 | header("Location: " . $_SERVER["PHP_SELF"] . "?mode=" . $mode . $param . ($page_y ? '&page_y=' . $page_y : '')); |
||||
325 | exit; |
||||
326 | } elseif ($action == 'reset' && $user->admin && GETPOST('confirm') == 'yes') { |
||||
327 | $result = unActivateModule($value); |
||||
328 | dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", getDolGlobalInt('MAIN_IHM_PARAMS_REV') + 1, 'chaine', 0, '', $conf->entity); |
||||
329 | if ($result) { |
||||
330 | setEventMessages($result, null, 'errors'); |
||||
331 | } |
||||
332 | header("Location: " . $_SERVER["PHP_SELF"] . "?mode=" . $mode . $param . ($page_y ? '&page_y=' . $page_y : '')); |
||||
333 | exit; |
||||
334 | } elseif (getDolGlobalInt("MAIN_FEATURES_LEVEL") > 1 && $action == 'reload' && $user->admin && GETPOST('confirm') == 'yes') { |
||||
335 | $result = unActivateModule($value, 0); |
||||
336 | dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int)$conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity); |
||||
337 | if ($result) { |
||||
338 | setEventMessages($result, null, 'errors'); |
||||
339 | header("Location: " . $_SERVER["PHP_SELF"] . "?mode=" . $mode . $param . ($page_y ? '&page_y=' . $page_y : '')); |
||||
340 | } |
||||
341 | $resarray = activateModule($value, 0, 1); |
||||
342 | dolibarr_set_const($db, "MAIN_IHM_PARAMS_REV", (int)$conf->global->MAIN_IHM_PARAMS_REV + 1, 'chaine', 0, '', $conf->entity); |
||||
343 | if (!empty($resarray['errors'])) { |
||||
344 | setEventMessages('', $resarray['errors'], 'errors'); |
||||
345 | } else { |
||||
346 | if ($resarray['nbperms'] > 0) { |
||||
347 | $tmpsql = "SELECT COUNT(rowid) as nb FROM " . MAIN_DB_PREFIX . "user WHERE admin <> 1"; |
||||
348 | $resqltmp = $db->query($tmpsql); |
||||
349 | if ($resqltmp) { |
||||
350 | $obj = $db->fetch_object($resqltmp); |
||||
351 | if ($obj && $obj->nb > 1) { |
||||
352 | $msg = $langs->trans('ModuleEnabledAdminMustCheckRights'); |
||||
353 | setEventMessages($msg, null, 'warnings'); |
||||
354 | } |
||||
355 | } else { |
||||
356 | dol_print_error($db); |
||||
357 | } |
||||
358 | } |
||||
359 | } |
||||
360 | header("Location: " . $_SERVER["PHP_SELF"] . "?mode=" . $mode . $param . ($page_y ? '&page_y=' . $page_y : '')); |
||||
361 | exit; |
||||
362 | } |
||||
363 | |||||
364 | /* |
||||
365 | * View |
||||
366 | */ |
||||
367 | |||||
368 | $form = new Form($db); |
||||
369 | |||||
370 | $morejs = array(); |
||||
371 | $morecss = array("/htdocs/admin/dolistore/css/dolistore.css"); |
||||
372 | |||||
373 | // Set dir where external modules are installed |
||||
374 | if (!dol_is_dir($dirins)) { |
||||
375 | dol_mkdir($dirins); |
||||
376 | } |
||||
377 | $dirins_ok = (dol_is_dir($dirins)); |
||||
378 | |||||
379 | $help_url = 'EN:First_setup|FR:Premiers_paramétrages|ES:Primeras_configuraciones'; |
||||
380 | ViewMain::llxHeader('', $langs->trans("Setup"), $help_url, '', '', '', $morejs, $morecss, 0, 'mod-admin page-modules'); |
||||
381 | |||||
382 | |||||
383 | // Search modules dirs |
||||
384 | $modulesdir = dolGetModulesDirs(); |
||||
385 | |||||
386 | $arrayofnatures = array( |
||||
387 | 'core' => array('label' => $langs->transnoentitiesnoconv("NativeModules")), |
||||
388 | 'external' => array('label' => $langs->transnoentitiesnoconv("External") . ' - [' . $langs->trans("AllPublishers") . ']') |
||||
389 | ); |
||||
390 | $arrayofwarnings = array(); // Array of warning each module want to show when activated |
||||
391 | $arrayofwarningsext = array(); // Array of warning each module want to show when we activate an external module |
||||
392 | $filenames = array(); |
||||
393 | $modules = array(); |
||||
394 | $orders = array(); |
||||
395 | $categ = array(); |
||||
396 | $publisherlogoarray = array(); |
||||
397 | |||||
398 | $i = 0; // is a sequencer of modules found |
||||
399 | $j = 0; // j is module number. Automatically affected if module number not defined. |
||||
400 | $modNameLoaded = array(); |
||||
401 | |||||
402 | $allModules = DolibarrModules::getModules($modulesdir); |
||||
403 | $main_features_level = getDolGlobalInt('MAIN_FEATURES_LEVEL'); |
||||
404 | foreach ($allModules as $modName => $filename) { |
||||
405 | $dir = dirname($filename) . DIRECTORY_SEPARATOR; |
||||
406 | |||||
407 | if (!empty($modNameLoaded[$modName])) { // In cache of already loaded modules ? |
||||
408 | $mesg = "Error: Module " . $modName . " was found twice: Into " . $modNameLoaded[$modName] . " and " . $dir . ". You probably have an old file on your disk.<br>"; |
||||
409 | dump(['msg ' . $modName => $mesg]); |
||||
410 | setEventMessages($mesg, null, 'warnings'); |
||||
411 | dol_syslog($mesg, LOG_ERR); |
||||
412 | continue; |
||||
413 | } |
||||
414 | |||||
415 | try { |
||||
416 | $objMod = DolibarrModules::getObj($db, $modName, $filename); |
||||
417 | if (!isset($objMod)) { |
||||
418 | print info_admin("admin/modules.php Warning bad descriptor file : " . $filename . " (Class " . $modName . " not found into file)", 0, 0, '1', 'warning'); |
||||
419 | continue; |
||||
420 | } |
||||
421 | |||||
422 | '@phan-var-force DolibarrModules $objMod'; |
||||
423 | $modNameLoaded[$modName] = $dir; |
||||
424 | if (!$objMod->numero > 0 && $modName != 'modUser') { |
||||
425 | dol_syslog('The module descriptor ' . $modName . ' must have a numero property', LOG_ERR); |
||||
426 | } |
||||
427 | $j = $objMod->numero; |
||||
428 | |||||
429 | $modulequalified = 1; |
||||
430 | |||||
431 | // We discard modules according to features level (PS: if module is activated we always show it) |
||||
432 | $const_name = 'MAIN_MODULE_' . strtoupper(preg_replace('/^mod/i', '', $modName)); |
||||
433 | |||||
434 | if (!DolibarrModules::isActivated($modName)) { |
||||
435 | if ($objMod->isDevelopment() && $main_features_level < 2) { |
||||
436 | dol_syslog("Module " . $modName . " is not active"); |
||||
437 | continue; |
||||
438 | } |
||||
439 | |||||
440 | if ($objMod->isExperimental() && $main_features_level < 1) { |
||||
441 | dol_syslog("Module " . $modName . " is experimental"); |
||||
442 | continue; |
||||
443 | } |
||||
444 | |||||
445 | if ($objMod->isDeprecated() && $main_features_level >= 0) { |
||||
446 | dol_syslog("Module " . $modName . " is deprecated"); |
||||
447 | continue; |
||||
448 | } |
||||
449 | } |
||||
450 | |||||
451 | // We discard modules according to property->hidden |
||||
452 | if (!empty($objMod->hidden)) { |
||||
453 | dol_syslog("Module " . $modName . " is hidden"); |
||||
454 | continue; |
||||
455 | } |
||||
456 | |||||
457 | $publisher = dol_escape_htmltag($objMod->getPublisher()); |
||||
458 | $external = ($objMod->isCoreOrExternalModule() == 'external'); |
||||
459 | if ($external) { |
||||
460 | if ($publisher) { |
||||
461 | // Check if there is a logo forpublisher |
||||
462 | /* Do not show the company logo in combo. Make combo list dirty. |
||||
463 | if (!empty($objMod->editor_squarred_logo)) { |
||||
464 | $publisherlogoarray['external_'.$publisher] = img_picto('', $objMod->editor_squarred_logo, 'class="publisherlogoinline"'); |
||||
465 | } |
||||
466 | $publisherlogo = empty($publisherlogoarray['external_'.$publisher]) ? '' : $publisherlogoarray['external_'.$publisher]; |
||||
467 | */ |
||||
468 | $arrayofnatures['external_' . $publisher] = array('label' => $langs->trans("External") . ' - ' . $publisher, 'data-html' => $langs->trans("External") . ' - <span class="opacitymedium inine-block valignmiddle">' . $publisher . '</span>'); |
||||
469 | } else { |
||||
470 | $arrayofnatures['external_'] = array('label' => $langs->trans("External") . ' - [' . $langs->trans("UnknownPublishers") . ']'); |
||||
471 | } |
||||
472 | } |
||||
473 | ksort($arrayofnatures); |
||||
474 | |||||
475 | // Define array $categ with categ with at least one qualified module |
||||
476 | $filenames[$i] = $modName; |
||||
477 | $modules[$modName] = $objMod; |
||||
478 | |||||
479 | // Gives the possibility to the module, to provide his own family info and position of this family |
||||
480 | if (is_array($objMod->familyinfo) && !empty($objMod->familyinfo)) { |
||||
481 | $familyinfo = array_merge($familyinfo, $objMod->familyinfo); |
||||
482 | $familykey = key($objMod->familyinfo); |
||||
483 | } else { |
||||
484 | $familykey = $objMod->family; |
||||
485 | } |
||||
486 | '@phan-var-force string $familykey'; // if not, phan considers $familykey may be null |
||||
487 | |||||
488 | $moduleposition = ($objMod->module_position ? $objMod->module_position : '50'); |
||||
489 | if ($objMod->isCoreOrExternalModule() == 'external' && $moduleposition < 100000) { |
||||
490 | // an external module should never return a value lower than '80'. |
||||
491 | $moduleposition = '80'; // External modules at end by default |
||||
492 | } |
||||
493 | |||||
494 | // Add list of warnings to show into arrayofwarnings and arrayofwarningsext |
||||
495 | if (!empty($objMod->warnings_activation)) { |
||||
496 | $arrayofwarnings[$modName] = $objMod->warnings_activation; |
||||
497 | } |
||||
498 | if (!empty($objMod->warnings_activation_ext)) { |
||||
499 | $arrayofwarningsext[$modName] = $objMod->warnings_activation_ext; |
||||
500 | } |
||||
501 | |||||
502 | $familyposition = (empty($familyinfo[$familykey]['position']) ? '0' : $familyinfo[$familykey]['position']); |
||||
503 | $listOfOfficialModuleGroups = array('hr', 'technic', 'interface', 'technic', 'portal', 'financial', 'crm', 'base', 'products', 'srm', 'ecm', 'projects', 'other'); |
||||
504 | if ($external && !in_array($familykey, $listOfOfficialModuleGroups)) { |
||||
505 | // If module is extern and into a custom group (not into an official predefined one), it must appear at end (custom groups should not be before official groups). |
||||
506 | if (is_numeric($familyposition)) { |
||||
507 | $familyposition = sprintf("%03d", (int)$familyposition + 100); |
||||
508 | } |
||||
509 | } |
||||
510 | |||||
511 | $orders[$i] = $familyposition . "_" . $familykey . "_" . $moduleposition . "_" . $j; // Sort by family, then by module position then number |
||||
512 | |||||
513 | // Set categ[$i] |
||||
514 | $specialstring = 'unknown'; |
||||
515 | if ($objMod->version == 'development' || $objMod->version == 'experimental') { |
||||
516 | $specialstring = 'expdev'; |
||||
517 | } |
||||
518 | if (isset($categ[$specialstring])) { |
||||
519 | $categ[$specialstring]++; // Array of all different modules categories |
||||
520 | } else { |
||||
521 | $categ[$specialstring] = 1; |
||||
522 | } |
||||
523 | $j++; |
||||
524 | $i++; |
||||
525 | } catch (Exception $e) { |
||||
526 | dol_syslog("Failed to load " . $filename . " " . $e->getMessage(), LOG_ERR); |
||||
527 | } |
||||
528 | } |
||||
529 | |||||
530 | if ($action == 'reset_confirm' && $user->admin) { |
||||
531 | if (!empty($modules[$value])) { |
||||
532 | $objMod = $modules[$value]; |
||||
533 | |||||
534 | if (!empty($objMod->langfiles)) { |
||||
535 | $langs->loadLangs($objMod->langfiles); |
||||
536 | } |
||||
537 | |||||
538 | $form = new Form($db); |
||||
539 | $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?value=' . $value . '&mode=' . $mode . $param, $langs->trans('ConfirmUnactivation'), $langs->trans(GETPOST('confirm_message_code')), 'reset', '', 'no', 1); |
||||
540 | } |
||||
541 | } |
||||
542 | |||||
543 | if ($action == 'reload_confirm' && $user->admin) { |
||||
544 | if (!empty($modules[$value])) { |
||||
545 | $objMod = $modules[$value]; |
||||
546 | |||||
547 | if (!empty($objMod->langfiles)) { |
||||
548 | $langs->loadLangs($objMod->langfiles); |
||||
549 | } |
||||
550 | |||||
551 | $form = new Form($db); |
||||
552 | $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?value=' . $value . '&mode=' . $mode . $param, $langs->trans('ConfirmReload'), $langs->trans(GETPOST('confirm_message_code')), 'reload', '', 'no', 1); |
||||
553 | } |
||||
554 | } |
||||
555 | |||||
556 | print $formconfirm; |
||||
557 | |||||
558 | asort($orders); |
||||
559 | //var_dump($orders); |
||||
560 | //var_dump($categ); |
||||
561 | //var_dump($modules); |
||||
562 | |||||
563 | $nbofactivatedmodules = count($conf->modules); |
||||
564 | |||||
565 | // Define $nbmodulesnotautoenabled - TODO This code is at different places |
||||
566 | $nbmodulesnotautoenabled = count($conf->modules); |
||||
567 | $listofmodulesautoenabled = array('agenda', 'fckeditor', 'export', 'import'); |
||||
568 | foreach ($listofmodulesautoenabled as $moduleautoenable) { |
||||
569 | if (in_array($moduleautoenable, $conf->modules)) { |
||||
570 | $nbmodulesnotautoenabled--; |
||||
571 | } |
||||
572 | } |
||||
573 | |||||
574 | print load_fiche_titre($langs->trans("ModulesSetup"), '', 'title_setup'); |
||||
575 | |||||
576 | // Start to show page |
||||
577 | $deschelp = ''; |
||||
578 | if ($mode == 'common' || $mode == 'commonkanban') { |
||||
579 | $desc = $langs->trans("ModulesDesc", '{picto}'); |
||||
580 | $desc .= ' ' . $langs->trans("ModulesDesc2", '{picto2}'); |
||||
581 | $desc = str_replace('{picto}', img_picto('', 'switch_off', 'class="size15x"'), $desc); |
||||
582 | $desc = str_replace('{picto2}', img_picto('', 'setup', 'class="size15x"'), $desc); |
||||
583 | if ($nbmodulesnotautoenabled <= getDolGlobalInt('MAIN_MIN_NB_ENABLED_MODULE_FOR_WARNING', 1)) { // If only minimal initial modules enabled |
||||
584 | $deschelp .= '<div class="info hideonsmartphone">' . $desc . "<br></div>\n"; |
||||
585 | } |
||||
586 | if (getDolGlobalString('MAIN_SETUP_MODULES_INFO')) { // Show a custom message |
||||
587 | $deschelp .= '<div class="info">' . $langs->trans(getDolGlobalString('MAIN_SETUP_MODULES_INFO')) . "<br></div>\n"; |
||||
588 | } |
||||
589 | if ($deschelp) { |
||||
590 | $deschelp .= '<br>'; |
||||
591 | } |
||||
592 | } |
||||
593 | |||||
594 | if ($mode == 'marketplace') { |
||||
595 | //$deschelp = '<div class="info hideonsmartphone">'.$langs->trans("ModulesMarketPlaceDesc")."<br></div><br>\n"; |
||||
596 | } |
||||
597 | |||||
598 | if ($mode == 'deploy') { |
||||
599 | $deschelp = '<div class="info hideonsmartphone">' . $langs->trans("ModulesDeployDesc", $langs->transnoentitiesnoconv("AvailableModules")) . "<br></div><br>\n"; |
||||
600 | } |
||||
601 | |||||
602 | if ($mode == 'develop') { |
||||
603 | $deschelp = '<div class="info hideonsmartphone">' . $langs->trans("ModulesDevelopDesc") . "<br></div><br>\n"; |
||||
604 | } |
||||
605 | |||||
606 | $head = modules_prepare_head($nbofactivatedmodules, count($modules), $nbmodulesnotautoenabled); |
||||
607 | |||||
608 | if ($mode == 'common' || $mode == 'commonkanban') { |
||||
609 | dol_set_focus('#search_keyword'); |
||||
610 | |||||
611 | print '<form method="POST" id="searchFormList" action="' . $_SERVER["PHP_SELF"] . '">'; |
||||
612 | print '<input type="hidden" name="token" value="' . newToken() . '">'; |
||||
613 | if (isset($optioncss) && $optioncss != '') { |
||||
614 | print '<input type="hidden" name="optioncss" value="' . $optioncss . '">'; |
||||
615 | } |
||||
616 | if (isset($sortfield) && $sortfield != '') { |
||||
617 | print '<input type="hidden" name="sortfield" value="' . $sortfield . '">'; |
||||
618 | } |
||||
619 | if (isset($sortorder) && $sortorder != '') { |
||||
620 | print '<input type="hidden" name="sortorder" value="' . $sortorder . '">'; |
||||
621 | } |
||||
622 | if (isset($page) && $page != '') { |
||||
623 | print '<input type="hidden" name="page" value="' . $page . '">'; |
||||
624 | } |
||||
625 | print '<input type="hidden" name="mode" value="' . $mode . '">'; |
||||
626 | |||||
627 | print dol_get_fiche_head($head, 'modules', '', -1); |
||||
628 | |||||
629 | print $deschelp; |
||||
630 | |||||
631 | $moreforfilter = '<div class="valignmiddle">'; |
||||
632 | |||||
633 | $moreforfilter .= '<div class="floatright right pagination paddingtop --module-list"><ul><li>'; |
||||
634 | $moreforfilter .= dolGetButtonTitle($langs->trans('CheckForModuleUpdate'), $langs->trans('CheckForModuleUpdate') . '<br>' . $langs->trans('CheckForModuleUpdateHelp'), 'fa fa-sync', $_SERVER["PHP_SELF"] . '?action=checklastversion&token=' . newToken() . '&mode=' . $mode . $param, '', 1, array('morecss' => 'reposition')); |
||||
635 | $moreforfilter .= dolGetButtonTitleSeparator(); |
||||
636 | $moreforfilter .= dolGetButtonTitle($langs->trans('ViewList'), '', 'fa fa-bars imgforviewmode', $_SERVER["PHP_SELF"] . '?mode=common' . $param, '', ($mode == 'common' ? 2 : 1), array('morecss' => 'reposition')); |
||||
637 | $moreforfilter .= dolGetButtonTitle($langs->trans('ViewKanban'), '', 'fa fa-th-list imgforviewmode', $_SERVER["PHP_SELF"] . '?mode=commonkanban' . $param, '', ($mode == 'commonkanban' ? 2 : 1), array('morecss' => 'reposition')); |
||||
638 | $moreforfilter .= '</li></ul></div>'; |
||||
639 | |||||
640 | $moreforfilter .= '<div class="divfilteralone colorbacktimesheet float valignmiddle">'; |
||||
641 | $moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">'; |
||||
642 | $moreforfilter .= img_picto($langs->trans("Filter"), 'filter', 'class="paddingright opacityhigh hideonsmartphone"') . '<input type="text" id="search_keyword" name="search_keyword" class="maxwidth125" value="' . dol_escape_htmltag($search_keyword) . '" placeholder="' . dol_escape_htmltag($langs->trans('Keyword')) . '">'; |
||||
643 | $moreforfilter .= '</div>'; |
||||
644 | $moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">'; |
||||
645 | $moreforfilter .= $form->selectarray('search_nature', $arrayofnatures, dol_escape_htmltag($search_nature), $langs->trans('Origin'), 0, 0, '', 0, 0, 0, '', 'maxwidth250', 1); |
||||
646 | $moreforfilter .= '</div>'; |
||||
647 | |||||
648 | if (getDolGlobalInt('MAIN_FEATURES_LEVEL')) { |
||||
649 | $array_version = array('stable' => $langs->transnoentitiesnoconv("Stable")); |
||||
650 | if (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 0) { |
||||
651 | $array_version['deprecated'] = $langs->trans("Deprecated"); |
||||
652 | } |
||||
653 | if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 0) { |
||||
654 | $array_version['experimental'] = $langs->trans("Experimental"); |
||||
655 | } |
||||
656 | if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 1) { |
||||
657 | $array_version['development'] = $langs->trans("Development"); |
||||
658 | } |
||||
659 | $moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">'; |
||||
660 | $moreforfilter .= $form->selectarray('search_version', $array_version, $search_version, $langs->transnoentitiesnoconv('Version'), 0, 0, '', 0, 0, 0, '', 'maxwidth150', 1); |
||||
661 | $moreforfilter .= '</div>'; |
||||
662 | } |
||||
663 | $array_status = array('active' => $langs->transnoentitiesnoconv("Enabled"), 'disabled' => $langs->transnoentitiesnoconv("Disabled")); |
||||
664 | $moreforfilter .= '<div class="divsearchfield paddingtop paddingbottom valignmiddle inline-block">'; |
||||
665 | $moreforfilter .= $form->selectarray('search_status', $array_status, $search_status, $langs->transnoentitiesnoconv('Status'), 0, 0, '', 0, 0, 0, '', 'maxwidth150', 1); |
||||
666 | $moreforfilter .= '</div>'; |
||||
667 | $moreforfilter .= ' '; |
||||
668 | $moreforfilter .= '<div class="divsearchfield valignmiddle inline-block">'; |
||||
669 | $moreforfilter .= '<input type="submit" name="buttonsubmit" class="button small nomarginleft" value="' . dol_escape_htmltag($langs->trans("Refresh")) . '">'; |
||||
670 | if ($search_keyword || ($search_nature && $search_nature != '-1') || ($search_version && $search_version != '-1') || ($search_status && $search_status != '-1')) { |
||||
671 | $moreforfilter .= ' '; |
||||
672 | $moreforfilter .= '<input type="submit" name="buttonreset" class="buttonreset noborderbottom" value="' . dol_escape_htmltag($langs->trans("Reset")) . '">'; |
||||
673 | } |
||||
674 | $moreforfilter .= '</div>'; |
||||
675 | $moreforfilter .= '</div>'; |
||||
676 | |||||
677 | $moreforfilter .= '</div>'; |
||||
678 | |||||
679 | if (!empty($moreforfilter)) { |
||||
680 | print $moreforfilter; |
||||
681 | $parameters = array(); |
||||
682 | $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters); // Note that $action and $object may have been modified by hook |
||||
683 | print $hookmanager->resPrint; |
||||
684 | } |
||||
685 | |||||
686 | $moreforfilter = ''; |
||||
687 | |||||
688 | print '<div class="clearboth"></div><br>'; |
||||
689 | |||||
690 | $object = new stdClass(); |
||||
691 | $parameters = array(); |
||||
692 | $reshook = $hookmanager->executeHooks('insertExtraHeader', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks |
||||
693 | if ($reshook < 0) { |
||||
694 | setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); |
||||
695 | } |
||||
696 | |||||
697 | $disabled_modules = array(); |
||||
698 | if (!empty($_SESSION["disablemodules"])) { |
||||
699 | $disabled_modules = explode(',', $_SESSION["disablemodules"]); |
||||
700 | } |
||||
701 | |||||
702 | // Show list of modules |
||||
703 | $oldfamily = ''; |
||||
704 | $foundoneexternalmodulewithupdate = 0; |
||||
705 | $linenum = 0; |
||||
706 | $atleastonequalified = 0; |
||||
707 | $atleastoneforfamily = 0; |
||||
708 | |||||
709 | foreach ($orders as $key => $value) { |
||||
710 | $linenum++; |
||||
711 | $tab = explode('_', $value); |
||||
712 | $familykey = $tab[1]; |
||||
713 | $module_position = $tab[2]; |
||||
714 | |||||
715 | $modName = $filenames[$key]; |
||||
716 | |||||
717 | if (!isset($modules[$modName])) { |
||||
718 | continue; |
||||
719 | } |
||||
720 | |||||
721 | /** @var DolibarrModules $objMod */ |
||||
722 | $objMod = $modules[$modName]; |
||||
723 | |||||
724 | //print $objMod->name." - ".$key." - ".$objMod->version."<br>"; |
||||
725 | if ($mode == 'expdev' && $objMod->version != 'development' && $objMod->version != 'experimental') { |
||||
726 | continue; // Discard if not for current tab |
||||
727 | } |
||||
728 | |||||
729 | if (!$objMod->getName()) { |
||||
730 | dol_syslog("Error for module " . $key . " - Property name of module looks empty", LOG_WARNING); |
||||
731 | continue; |
||||
732 | } |
||||
733 | |||||
734 | $modulenameshort = strtolower(preg_replace('/^mod/i', '', get_only_class($objMod))); |
||||
735 | $const_name = 'MAIN_MODULE_' . strtoupper(preg_replace('/^mod/i', '', get_only_class($objMod))); |
||||
736 | |||||
737 | // Check filters |
||||
738 | $modulename = $objMod->getName(); |
||||
739 | $moduletechnicalname = $objMod->name; |
||||
740 | $moduledesc = $objMod->getDesc(); |
||||
741 | $moduledesclong = $objMod->getDescLong(); |
||||
742 | $moduleauthor = $objMod->getPublisher(); |
||||
743 | |||||
744 | // We discard showing according to filters |
||||
745 | if ($search_keyword) { |
||||
746 | $qualified = 0; |
||||
747 | if ( |
||||
748 | preg_match('/' . preg_quote($search_keyword, '/') . '/i', $modulename) |
||||
749 | || preg_match('/' . preg_quote($search_keyword, '/') . '/i', $moduletechnicalname) |
||||
750 | || ($moduledesc && preg_match('/' . preg_quote($search_keyword, '/') . '/i', $moduledesc)) |
||||
751 | || ($moduledesclong && preg_match('/' . preg_quote($search_keyword, '/') . '/i', $moduledesclong)) |
||||
752 | || ($moduleauthor && preg_match('/' . preg_quote($search_keyword, '/') . '/i', $moduleauthor)) |
||||
753 | ) { |
||||
754 | $qualified = 1; |
||||
755 | } |
||||
756 | if (!$qualified) { |
||||
757 | continue; |
||||
758 | } |
||||
759 | } |
||||
760 | if ($search_status) { |
||||
761 | if ($search_status == 'active' && !getDolGlobalString($const_name)) { |
||||
762 | continue; |
||||
763 | } |
||||
764 | if ($search_status == 'disabled' && getDolGlobalString($const_name)) { |
||||
765 | continue; |
||||
766 | } |
||||
767 | } |
||||
768 | if ($search_nature) { |
||||
769 | if (preg_match('/^external/', $search_nature) && $objMod->isCoreOrExternalModule() != 'external') { |
||||
770 | continue; |
||||
771 | } |
||||
772 | $reg = array(); |
||||
773 | if (preg_match('/^external_(.*)$/', $search_nature, $reg)) { |
||||
774 | //print $reg[1].'-'.dol_escape_htmltag($objMod->getPublisher()); |
||||
775 | $publisher = dol_escape_htmltag($objMod->getPublisher()); |
||||
776 | if ($reg[1] && dol_escape_htmltag($reg[1]) != $publisher) { |
||||
777 | continue; |
||||
778 | } |
||||
779 | if (!$reg[1] && !empty($publisher)) { |
||||
780 | continue; |
||||
781 | } |
||||
782 | } |
||||
783 | if ($search_nature == 'core' && $objMod->isCoreOrExternalModule() == 'external') { |
||||
784 | continue; |
||||
785 | } |
||||
786 | } |
||||
787 | if ($search_version) { |
||||
788 | if (($objMod->version == 'development' || $objMod->version == 'experimental' || preg_match('/deprecated/', $objMod->version)) && $search_version == 'stable') { |
||||
789 | continue; |
||||
790 | } |
||||
791 | if ($objMod->version != 'development' && ($search_version == 'development')) { |
||||
792 | continue; |
||||
793 | } |
||||
794 | if ($objMod->version != 'experimental' && ($search_version == 'experimental')) { |
||||
795 | continue; |
||||
796 | } |
||||
797 | if (!preg_match('/deprecated/', $objMod->version) && ($search_version == 'deprecated')) { |
||||
798 | continue; |
||||
799 | } |
||||
800 | } |
||||
801 | |||||
802 | $atleastonequalified++; |
||||
803 | |||||
804 | // Load all language files of the qualified module |
||||
805 | if (isset($objMod->langfiles) && is_array($objMod->langfiles)) { |
||||
806 | foreach ($objMod->langfiles as $domain) { |
||||
807 | $langs->load($domain); |
||||
808 | } |
||||
809 | } |
||||
810 | |||||
811 | // Print a separator if we change family |
||||
812 | if ($familykey != $oldfamily) { |
||||
813 | if ($oldfamily) { |
||||
814 | print '</table></div><br>'; |
||||
815 | } |
||||
816 | |||||
817 | $familytext = empty($familyinfo[$familykey]['label']) ? $familykey : $familyinfo[$familykey]['label']; |
||||
818 | |||||
819 | print load_fiche_titre($familytext, '', '', 0, '', 'modulefamilygroup'); |
||||
820 | |||||
821 | if ($mode == 'commonkanban') { |
||||
822 | print '<div class="box-flex-container kanban">'; |
||||
823 | } else { |
||||
824 | print '<div class="div-table-responsive">'; |
||||
825 | print '<table class="tagtable liste" summary="list_of_modules">' . "\n"; |
||||
826 | } |
||||
827 | |||||
828 | $atleastoneforfamily = 0; |
||||
829 | } |
||||
830 | |||||
831 | $atleastoneforfamily++; |
||||
832 | |||||
833 | if ($familykey != $oldfamily) { |
||||
834 | $familytext = empty($familyinfo[$familykey]['label']) ? $familykey : $familyinfo[$familykey]['label']; |
||||
835 | $oldfamily = $familykey; |
||||
836 | } |
||||
837 | |||||
838 | // Version (with picto warning or not) |
||||
839 | $version = $objMod->getVersion(0); |
||||
840 | $versiontrans = ''; |
||||
841 | $warningstring = ''; |
||||
842 | if (preg_match('/development/i', $version)) { |
||||
843 | $warningstring = $langs->trans("Development"); |
||||
844 | } |
||||
845 | if (preg_match('/experimental/i', $version)) { |
||||
846 | $warningstring = $langs->trans("Experimental"); |
||||
847 | } |
||||
848 | if (preg_match('/deprecated/i', $version)) { |
||||
849 | $warningstring = $langs->trans("Deprecated"); |
||||
850 | } |
||||
851 | |||||
852 | if ($objMod->isCoreOrExternalModule() == 'external' || preg_match('/development|experimental|deprecated/i', $version)) { |
||||
853 | $versiontrans .= $objMod->getVersion(1); |
||||
854 | } |
||||
855 | |||||
856 | if ( |
||||
857 | $objMod->isCoreOrExternalModule() == 'external' |
||||
858 | && ( |
||||
859 | $action == 'checklastversion' |
||||
860 | // This is a bad practice to activate a check on an external access during the building of the admin page. 1 external module can hang the application. |
||||
861 | // Adding a cron job could be a good idea: see DolibarrModules::checkForUpdate() |
||||
862 | || getDolGlobalString('CHECKLASTVERSION_EXTERNALMODULE') |
||||
863 | ) |
||||
864 | ) { |
||||
865 | $checkRes = $objMod->checkForUpdate(); |
||||
866 | if ($checkRes > 0) { |
||||
867 | setEventMessage($objMod->getName() . ' : ' . $versiontrans . ' -> ' . $objMod->lastVersion); |
||||
868 | } elseif ($checkRes < 0) { |
||||
869 | setEventMessage($objMod->getName() . ' ' . $langs->trans('CheckVersionFail'), 'warnings'); |
||||
870 | } |
||||
871 | } |
||||
872 | |||||
873 | // Define imginfo |
||||
874 | $imginfo = "info"; |
||||
875 | if ($objMod->isCoreOrExternalModule() == 'external') { |
||||
876 | $imginfo = "info_black"; |
||||
877 | } |
||||
878 | |||||
879 | $codeenabledisable = ''; |
||||
880 | $codetoconfig = ''; |
||||
881 | |||||
882 | // Force disable of module disabled into session (for demo for example) |
||||
883 | if (in_array($modulenameshort, $disabled_modules)) { |
||||
884 | $objMod->disabled = true; |
||||
885 | } |
||||
886 | |||||
887 | // Activate/Disable and Setup (2 columns) |
||||
888 | if (DolibarrModules::isActivated($modName)) { |
||||
889 | // Set $codeenabledisable |
||||
890 | $disableSetup = 0; |
||||
891 | if (!empty($arrayofwarnings[$modName])) { |
||||
892 | $codeenabledisable .= '<!-- This module has a warning to show when we activate it (note: your country is ' . $mysoc->country_code . ') -->' . "\n"; |
||||
893 | } |
||||
894 | |||||
895 | if (!empty($objMod->disabled)) { |
||||
896 | $codeenabledisable .= $langs->trans("Disabled"); |
||||
897 | } elseif (!empty($objMod->always_enabled) || ((isModEnabled('multicompany') && $objMod->core_enabled) && ($user->entity || $conf->entity != 1))) { |
||||
898 | // @phan-suppress-next-line PhanUndeclaredMethodCall |
||||
899 | if (method_exists($objMod, 'alreadyUsed') && $objMod->alreadyUsed()) { |
||||
900 | $codeenabledisable .= $langs->trans("Used"); |
||||
901 | } else { |
||||
902 | $codeenabledisable .= img_picto($langs->trans("Required"), 'switch_on', '', false, 0, 0, '', 'opacitymedium valignmiddle'); |
||||
903 | //print $langs->trans("Required"); |
||||
904 | } |
||||
905 | if (isModEnabled('multicompany') && $user->entity) { |
||||
906 | $disableSetup++; |
||||
907 | } |
||||
908 | } else { |
||||
909 | // @phan-suppress-next-line PhanUndeclaredMethodCall |
||||
910 | if (!empty($objMod->warnings_unactivation[$mysoc->country_code]) && method_exists($objMod, 'alreadyUsed') && $objMod->alreadyUsed()) { |
||||
911 | $codeenabledisable .= '<a class="reposition valignmiddle" href="' . $_SERVER["PHP_SELF"] . '?id=' . $objMod->numero . '&token=' . newToken() . '&module_position=' . $module_position . '&action=reset_confirm&confirm_message_code=' . urlencode($objMod->warnings_unactivation[$mysoc->country_code]) . '&value=' . $modName . '&mode=' . $mode . $param . '">'; |
||||
912 | $codeenabledisable .= img_picto($langs->trans("Activated") . ($warningstring ? ' ' . $warningstring : ''), 'switch_on'); |
||||
913 | $codeenabledisable .= '</a>'; |
||||
914 | if (getDolGlobalInt("MAIN_FEATURES_LEVEL") > 1) { |
||||
915 | $codeenabledisable .= ' '; |
||||
916 | $codeenabledisable .= '<a class="reposition" href="' . $_SERVER["PHP_SELF"] . '?id=' . $objMod->numero . '&token=' . newToken() . '&module_position=' . $module_position . '&action=reload_confirm&value=' . $modName . '&mode=' . $mode . '&confirm=yes' . $param . '">'; |
||||
917 | $codeenabledisable .= img_picto($langs->trans("Reload"), 'refresh', 'class="opacitymedium"'); |
||||
918 | $codeenabledisable .= '</a>'; |
||||
919 | } |
||||
920 | } else { |
||||
921 | $codeenabledisable .= '<a class="reposition valignmiddle" href="' . $_SERVER["PHP_SELF"] . '?id=' . $objMod->numero . '&token=' . newToken() . '&module_position=' . $module_position . '&action=reset&value=' . $modName . '&mode=' . $mode . '&confirm=yes' . $param . '">'; |
||||
922 | $codeenabledisable .= img_picto($langs->trans("Activated") . ($warningstring ? ' ' . $warningstring : ''), 'switch_on'); |
||||
923 | $codeenabledisable .= '</a>'; |
||||
924 | if (getDolGlobalInt("MAIN_FEATURES_LEVEL") > 1) { |
||||
925 | $codeenabledisable .= ' '; |
||||
926 | $codeenabledisable .= '<a class="reposition" href="' . $_SERVER["PHP_SELF"] . '?id=' . $objMod->numero . '&token=' . newToken() . '&module_position=' . $module_position . '&action=reload&value=' . $modName . '&mode=' . $mode . '&confirm=yes' . $param . '">'; |
||||
927 | $codeenabledisable .= img_picto($langs->trans("Reload"), 'refresh', 'class="opacitymedium"'); |
||||
928 | $codeenabledisable .= '</a>'; |
||||
929 | } |
||||
930 | } |
||||
931 | } |
||||
932 | |||||
933 | // Set $codetoconfig |
||||
934 | if (!empty($objMod->config_page_url) && !$disableSetup) { |
||||
935 | $backtourlparam = ''; |
||||
936 | if ($search_keyword != '') { |
||||
937 | $backtourlparam .= ($backtourlparam ? '&' : '?') . 'search_keyword=' . urlencode($search_keyword); // No urlencode here, done later |
||||
938 | } |
||||
939 | if ($search_nature > -1) { |
||||
940 | $backtourlparam .= ($backtourlparam ? '&' : '?') . 'search_nature=' . urlencode($search_nature); // No urlencode here, done later |
||||
941 | } |
||||
942 | if ($search_version > -1) { |
||||
943 | $backtourlparam .= ($backtourlparam ? '&' : '?') . 'search_version=' . urlencode($search_version); // No urlencode here, done later |
||||
944 | } |
||||
945 | if ($search_status > -1) { |
||||
946 | $backtourlparam .= ($backtourlparam ? '&' : '?') . 'search_status=' . urlencode($search_status); // No urlencode here, done later |
||||
947 | } |
||||
948 | $backtourl = $_SERVER["PHP_SELF"] . $backtourlparam; |
||||
949 | |||||
950 | $regs = array(); |
||||
951 | if (is_array($objMod->config_page_url)) { |
||||
952 | $i = 0; |
||||
953 | foreach ($objMod->config_page_url as $page) { |
||||
954 | $urlpage = $page; |
||||
955 | if ($i++) { |
||||
956 | $codetoconfig .= '<a href="' . $urlpage . '" title="' . $langs->trans($page) . '">' . img_picto(ucfirst($page), "setup") . '</a>'; |
||||
957 | // print '<a href="'.$page.'">'.ucfirst($page).'</a> '; |
||||
958 | } else { |
||||
959 | if (preg_match('/^([^@]+)@([^@]+)$/i', $urlpage, $regs)) { |
||||
960 | $urltouse = dol_buildpath('/' . $regs[2] . '/admin/' . $regs[1], 1); |
||||
961 | $codetoconfig .= '<a href="' . $urltouse . (preg_match('/\?/', $urltouse) ? '&' : '?') . 'save_lastsearch_values=1&backtopage=' . urlencode($backtourl) . '" title="' . $langs->trans("Setup") . '">' . img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15') . '</a>'; |
||||
962 | } else { |
||||
963 | $urltouse = $urlpage; |
||||
964 | $codetoconfig .= '<a href="' . $urltouse . (preg_match('/\?/', $urltouse) ? '&' : '?') . 'save_lastsearch_values=1&backtopage=' . urlencode($backtourl) . '" title="' . $langs->trans("Setup") . '">' . img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15') . '</a>'; |
||||
965 | } |
||||
966 | } |
||||
967 | } |
||||
968 | } elseif (preg_match('/^([^@]+)@([^@]+)$/i', (string)$objMod->config_page_url, $regs)) { |
||||
969 | $codetoconfig .= '<a class="valignmiddle" href="' . dol_buildpath('/' . $regs[2] . '/admin/' . $regs[1], 1) . '?save_lastsearch_values=1&backtopage=' . urlencode($backtourl) . '" title="' . $langs->trans("Setup") . '">' . img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15') . '</a>'; |
||||
970 | } else { |
||||
971 | $codetoconfig .= '<a class="valignmiddle" href="' . ((string)$objMod->config_page_url) . '?save_lastsearch_values=1&backtopage=' . urlencode($backtourl) . '" title="' . $langs->trans("Setup") . '">' . img_picto($langs->trans("Setup"), "setup", 'style="padding-right: 6px"', false, 0, 0, '', 'fa-15') . '</a>'; |
||||
972 | } |
||||
973 | } else { |
||||
974 | $codetoconfig .= img_picto($langs->trans("NothingToSetup"), "setup", 'class="opacitytransp" style="padding-right: 6px"', false, 0, 0, '', 'fa-15'); |
||||
975 | } |
||||
976 | } else { // Module not yet activated |
||||
977 | // Set $codeenabledisable |
||||
978 | if (!empty($objMod->always_enabled)) { |
||||
979 | // A 'always_enabled' module should not never be disabled. If this happen, we keep a link to re-enable it. |
||||
980 | $codeenabledisable .= '<!-- Message to show: an always_enabled module has been disabled -->' . "\n"; |
||||
981 | $codeenabledisable .= '<a class="reposition" href="' . $_SERVER["PHP_SELF"] . '?id=' . $objMod->numero . '&token=' . newToken() . '&module_position=' . $module_position . '&action=set&token=' . newToken() . '&value=' . $modName . '&mode=' . $mode . $param . '"'; |
||||
982 | $codeenabledisable .= '>'; |
||||
983 | $codeenabledisable .= img_picto($langs->trans("Disabled"), 'switch_off'); |
||||
984 | $codeenabledisable .= "</a>\n"; |
||||
985 | } elseif (!empty($objMod->disabled)) { |
||||
986 | $codeenabledisable .= $langs->trans("Disabled"); |
||||
987 | } else { |
||||
988 | // Module qualified for activation |
||||
989 | $warningmessage = ''; |
||||
990 | if (!empty($arrayofwarnings[$modName])) { |
||||
991 | $codeenabledisable .= '<!-- This module is a core module and it may have a warning to show when we activate it (note: your country is ' . $mysoc->country_code . ') -->' . "\n"; |
||||
992 | foreach ($arrayofwarnings[$modName] as $keycountry => $cursorwarningmessage) { |
||||
993 | if (preg_match('/^always/', $keycountry) || ($mysoc->country_code && preg_match('/^' . $mysoc->country_code . '/', $keycountry))) { |
||||
994 | $warningmessage .= ($warningmessage ? "\n" : "") . $langs->trans($cursorwarningmessage, $objMod->getName(), $mysoc->country_code); |
||||
995 | } |
||||
996 | } |
||||
997 | } |
||||
998 | if ($objMod->isCoreOrExternalModule() == 'external' && !empty($arrayofwarningsext)) { |
||||
999 | $codeenabledisable .= '<!-- This module is an external module and it may have a warning to show (note: your country is ' . $mysoc->country_code . ') -->' . "\n"; |
||||
1000 | foreach ($arrayofwarningsext as $keymodule => $arrayofwarningsextbycountry) { |
||||
1001 | $keymodulelowercase = strtolower(preg_replace('/^mod/', '', $keymodule)); |
||||
1002 | if (in_array($keymodulelowercase, $conf->modules)) { // If module that request warning is on |
||||
1003 | foreach ($arrayofwarningsextbycountry as $keycountry => $cursorwarningmessage) { |
||||
1004 | if (preg_match('/^always/', $keycountry) || ($mysoc->country_code && preg_match('/^' . $mysoc->country_code . '/', $keycountry))) { |
||||
1005 | $warningmessage .= ($warningmessage ? "\n" : "") . $langs->trans($cursorwarningmessage, $objMod->getName(), $mysoc->country_code, $modules[$keymodule]->getName()); |
||||
1006 | $warningmessage .= ($warningmessage ? "\n" : "") . ($warningmessage ? "\n" : "") . $langs->trans("Module") . ' : ' . $objMod->getName(); |
||||
1007 | if (!empty($objMod->editor_name)) { |
||||
1008 | $warningmessage .= ($warningmessage ? "\n" : "") . $langs->trans("Publisher") . ' : ' . $objMod->editor_name; |
||||
1009 | } |
||||
1010 | if (!empty($objMod->editor_name)) { |
||||
1011 | $warningmessage .= ($warningmessage ? "\n" : "") . $langs->trans("ModuleTriggeringThisWarning") . ' : ' . $modules[$keymodule]->getName(); |
||||
1012 | } |
||||
1013 | } |
||||
1014 | } |
||||
1015 | } |
||||
1016 | } |
||||
1017 | } |
||||
1018 | $codeenabledisable .= '<!-- Message to show: ' . $warningmessage . ' -->' . "\n"; |
||||
1019 | $codeenabledisable .= '<a class="reposition" href="' . $_SERVER["PHP_SELF"] . '?id=' . $objMod->numero . '&token=' . newToken() . '&module_position=' . $module_position . '&action=set&token=' . newToken() . '&value=' . $modName . '&mode=' . $mode . $param . '"'; |
||||
1020 | if ($warningmessage) { |
||||
1021 | $codeenabledisable .= ' onclick="return confirm(\'' . dol_escape_js($warningmessage) . '\');"'; |
||||
1022 | } |
||||
1023 | $codeenabledisable .= '>'; |
||||
1024 | $codeenabledisable .= img_picto($langs->trans("Disabled"), 'switch_off'); |
||||
1025 | $codeenabledisable .= "</a>\n"; |
||||
1026 | } |
||||
1027 | |||||
1028 | // Set $codetoconfig |
||||
1029 | $codetoconfig .= img_picto($langs->trans("NothingToSetup"), "setup", 'class="opacitytransp" style="padding-right: 6px"'); |
||||
1030 | } |
||||
1031 | |||||
1032 | if ($mode == 'commonkanban') { |
||||
1033 | // Output Kanban |
||||
1034 | print $objMod->getKanbanView($codeenabledisable, $codetoconfig); |
||||
1035 | } else { |
||||
1036 | print '<tr class="oddeven' . ($warningstring ? ' info-box-content-warning' : '') . '">' . "\n"; |
||||
1037 | if (getDolGlobalString('MAIN_MODULES_SHOW_LINENUMBERS')) { |
||||
1038 | print '<td class="width50">' . $linenum . '</td>'; |
||||
1039 | } |
||||
1040 | |||||
1041 | // Picto + Name of module |
||||
1042 | print ' <td class="tdoverflowmax200 minwidth200imp" title="' . dol_escape_htmltag($objMod->getName()) . '">'; |
||||
1043 | $alttext = ''; |
||||
1044 | //if (is_array($objMod->need_dolibarr_version)) $alttext.=($alttext?' - ':'').'Dolibarr >= '.join('.',$objMod->need_dolibarr_version); |
||||
1045 | //if (is_array($objMod->phpmin)) $alttext.=($alttext?' - ':'').'PHP >= '.join('.',$objMod->phpmin); |
||||
1046 | if (!empty($objMod->picto)) { |
||||
1047 | if (preg_match('/^\//i', $objMod->picto)) { |
||||
1048 | print img_picto($alttext, $objMod->picto, 'class="valignmiddle pictomodule paddingrightonly"', 1); |
||||
1049 | } else { |
||||
1050 | print img_object($alttext, $objMod->picto, 'class="valignmiddle pictomodule paddingrightonly"'); |
||||
1051 | } |
||||
1052 | } else { |
||||
1053 | print img_object($alttext, 'generic', 'class="valignmiddle paddingrightonly"'); |
||||
1054 | } |
||||
1055 | print ' <span class="valignmiddle">' . $objMod->getName() . '</span>'; |
||||
1056 | print "</td>\n"; |
||||
1057 | |||||
1058 | // Desc |
||||
1059 | print '<td class="valignmiddle tdoverflowmax300 minwidth200imp">'; |
||||
1060 | print nl2br($objMod->getDesc()); |
||||
1061 | print "</td>\n"; |
||||
1062 | |||||
1063 | // Help |
||||
1064 | print '<td class="center nowrap" style="width: 82px;">'; |
||||
1065 | //print $form->textwithpicto('', $text, 1, $imginfo, 'minheight20', 0, 2, 1); |
||||
1066 | print '<a href="javascript:document_preview(\'' . constant('BASE_URL') . '/admin/modulehelp.php?id=' . ((int)$objMod->numero) . '\',\'text/html\',\'' . dol_escape_js($langs->trans("Module")) . '\')">' . img_picto(($objMod->isCoreOrExternalModule() == 'external' ? $langs->trans("ExternalModule") . ' - ' : '') . $langs->trans("ClickToShowDescription"), $imginfo) . '</a>'; |
||||
1067 | print '</td>'; |
||||
1068 | |||||
1069 | // Version |
||||
1070 | print '<td class="center nowrap width150" title="' . dol_escape_htmltag(dol_string_nohtmltag($versiontrans)) . '">'; |
||||
1071 | if ($objMod->needUpdate) { |
||||
1072 | $versionTitle = $langs->trans('ModuleUpdateAvailable') . ' : ' . $objMod->lastVersion; |
||||
1073 | print '<span class="badge badge-warning classfortooltip" title="' . dol_escape_htmltag($versionTitle) . '">' . $versiontrans . '</span>'; |
||||
1074 | } else { |
||||
1075 | print $versiontrans; |
||||
1076 | } |
||||
1077 | print "</td>\n"; |
||||
1078 | |||||
1079 | // Link enable/disable |
||||
1080 | print '<td class="center valignmiddle left nowraponall" width="60px">'; |
||||
1081 | print $codeenabledisable; |
||||
1082 | print "</td>\n"; |
||||
1083 | |||||
1084 | // Link config |
||||
1085 | print '<td class="tdsetuppicto right valignmiddle" width="60px">'; |
||||
1086 | print $codetoconfig; |
||||
1087 | print '</td>'; |
||||
1088 | |||||
1089 | print "</tr>\n"; |
||||
1090 | } |
||||
1091 | if ($objMod->needUpdate) { |
||||
1092 | $foundoneexternalmodulewithupdate++; |
||||
1093 | } |
||||
1094 | } |
||||
1095 | |||||
1096 | if ($action == 'checklastversion') { |
||||
1097 | if ($foundoneexternalmodulewithupdate) { |
||||
1098 | setEventMessages($langs->trans("ModuleUpdateAvailable"), null, 'mesgs'); |
||||
1099 | } else { |
||||
1100 | setEventMessages($langs->trans("NoExternalModuleWithUpdate"), null, 'mesgs'); |
||||
1101 | } |
||||
1102 | } |
||||
1103 | |||||
1104 | if ($oldfamily) { |
||||
1105 | if ($mode == 'commonkanban') { |
||||
1106 | print '</div>'; |
||||
1107 | } else { |
||||
1108 | print "</table>\n"; |
||||
1109 | print '</div>'; |
||||
1110 | } |
||||
1111 | } |
||||
1112 | |||||
1113 | if (!$atleastonequalified) { |
||||
1114 | print '<br><span class="opacitymedium">' . $langs->trans("NoDeployedModulesFoundWithThisSearchCriteria") . '</span><br><br>'; |
||||
1115 | } |
||||
1116 | |||||
1117 | print dol_get_fiche_end(); |
||||
1118 | |||||
1119 | print '<br>'; |
||||
1120 | |||||
1121 | // Show warning about external users |
||||
1122 | print info_admin(showModulesExludedForExternal($modules)) . "\n"; |
||||
1123 | |||||
1124 | print '</form>'; |
||||
1125 | } |
||||
1126 | |||||
1127 | if ($mode == 'marketplace') { |
||||
1128 | print dol_get_fiche_head($head, $mode, '', -1); |
||||
1129 | |||||
1130 | print $deschelp; |
||||
1131 | |||||
1132 | print '<br>'; |
||||
1133 | |||||
1134 | // Marketplace |
||||
1135 | print '<div class="div-table-responsive-no-min">'; |
||||
1136 | print '<table summary="list_of_modules" class="noborder centpercent">' . "\n"; |
||||
1137 | print '<tr class="liste_titre">' . "\n"; |
||||
1138 | print '<td class="hideonsmartphone">' . $form->textwithpicto($langs->trans("Provider"), $langs->trans("WebSiteDesc")) . '</td>'; |
||||
1139 | print '<td></td>'; |
||||
1140 | print '<td>' . $langs->trans("URL") . '</td>'; |
||||
1141 | print '</tr>'; |
||||
1142 | |||||
1143 | print '<tr class="oddeven">' . "\n"; |
||||
1144 | $url = 'https://www.dolistore.com'; |
||||
1145 | print '<td class="hideonsmartphone"><a href="' . $url . '" target="_blank" rel="noopener noreferrer external"><img border="0" class="imgautosize imgmaxwidth180" src="' . constant('DOL_URL_ROOT') . '/theme/alxarafe_shop.png"></a></td>'; |
||||
1146 | print '<td><span class="opacitymedium">' . $langs->trans("DoliStoreDesc") . '</span></td>'; |
||||
1147 | print '<td><a href="' . $url . '" target="_blank" rel="noopener noreferrer external">' . $url . '</a></td>'; |
||||
1148 | print '</tr>'; |
||||
1149 | |||||
1150 | print "</table>\n"; |
||||
1151 | print '</div>'; |
||||
1152 | |||||
1153 | print dol_get_fiche_end(); |
||||
1154 | |||||
1155 | print '<br>'; |
||||
1156 | |||||
1157 | if (!getDolGlobalString('MAIN_DISABLE_DOLISTORE_SEARCH') && getDolGlobalInt('MAIN_FEATURES_LEVEL') >= 1) { |
||||
1158 | // $options is array with filter criteria |
||||
1159 | //var_dump($options); |
||||
1160 | $dolistore->getRemoteCategories(); |
||||
1161 | $dolistore->getRemoteProducts($options); |
||||
1162 | |||||
1163 | print '<span class="opacitymedium">' . $langs->trans('DOLISTOREdescriptionLong') . '</span><br><br>'; |
||||
1164 | |||||
1165 | $previouslink = $dolistore->get_previous_link(); |
||||
1166 | $nextlink = $dolistore->get_next_link(); |
||||
1167 | |||||
1168 | print '<div class="liste_titre liste_titre_bydiv centpercent"><div class="divsearchfield">'; |
||||
1169 | |||||
1170 | print '<form method="POST" class="centpercent" id="searchFormList" action="' . $dolistore->url . '">'; ?> |
||||
1171 | <input type="hidden" name="token" value="<?php echo newToken(); ?>"> |
||||
1172 | <input type="hidden" name="mode" value="marketplace"> |
||||
1173 | <div class="divsearchfield"> |
||||
1174 | <input name="search_keyword" placeholder="<?php echo $langs->trans('Keyword') ?>" id="search_keyword" |
||||
1175 | type="text" class="minwidth200" value="<?php echo dol_escape_htmltag($options['search']) ?>"><br> |
||||
1176 | </div> |
||||
1177 | <div class="divsearchfield"> |
||||
1178 | <input class="button buttongen" value="<?php echo $langs->trans('Rechercher') ?>" type="submit"> |
||||
1179 | <a class="buttonreset" |
||||
1180 | href="<?php echo urlencode($dolistore->url) ?>"><?php echo $langs->trans('Reset') ?></a> |
||||
1181 | </div> |
||||
1182 | <?php |
||||
1183 | print $previouslink; |
||||
1184 | print $nextlink; |
||||
1185 | print '</form>'; |
||||
1186 | |||||
1187 | print '</div></div>'; |
||||
1188 | print '<div class="clearboth"></div>'; |
||||
1189 | ?> |
||||
1190 | |||||
1191 | <div id="category-tree-left"> |
||||
1192 | <ul class="tree"> |
||||
1193 | <?php |
||||
1194 | echo $dolistore->get_categories(); // Do not use dol_escape_htmltag here, it is already a structured content?> |
||||
1195 | </ul> |
||||
1196 | </div> |
||||
1197 | <div id="listing-content"> |
||||
1198 | <table summary="list_of_modules" id="list_of_modules" class="productlist centpercent"> |
||||
1199 | <tbody id="listOfModules"> |
||||
1200 | <?php echo $dolistore->get_products(); ?> |
||||
1201 | </tbody> |
||||
1202 | </table> |
||||
1203 | </div> |
||||
1204 | <?php |
||||
1205 | } |
||||
1206 | } |
||||
1207 | |||||
1208 | |||||
1209 | // Install external module |
||||
1210 | |||||
1211 | if ($mode == 'deploy') { |
||||
1212 | print dol_get_fiche_head($head, $mode, '', -1); |
||||
1213 | |||||
1214 | $fullurl = '<a href="' . $urldolibarrmodules . '" target="_blank" rel="noopener noreferrer">' . $urldolibarrmodules . '</a>'; |
||||
1215 | $message = ''; |
||||
1216 | if ($allowonlineinstall) { |
||||
1217 | if (!in_array('/custom', explode(',', $dolibarr_main_url_root_alt))) { |
||||
1218 | $message = info_admin($langs->trans("ConfFileMustContainCustom", DOL_DOCUMENT_ROOT . '/custom', DOL_DOCUMENT_ROOT)); |
||||
1219 | $allowfromweb = -1; |
||||
1220 | } else { |
||||
1221 | if ($dirins_ok) { |
||||
1222 | if (!is_writable(dol_osencode($dirins))) { |
||||
1223 | $langs->load("errors"); |
||||
1224 | $message = info_admin($langs->trans("ErrorFailedToWriteInDir", $dirins), 0, 0, '1', 'warning'); |
||||
1225 | $allowfromweb = 0; |
||||
1226 | } |
||||
1227 | } else { |
||||
1228 | $message = info_admin($langs->trans("NotExistsDirect", $dirins) . $langs->trans("InfDirAlt") . $langs->trans("InfDirExample")); |
||||
1229 | $allowfromweb = 0; |
||||
1230 | } |
||||
1231 | } |
||||
1232 | } else { |
||||
1233 | if (getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')) { |
||||
1234 | // Show clean message |
||||
1235 | if (!is_numeric(getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US'))) { |
||||
1236 | $message = info_admin($langs->trans(getDolGlobalString('MAIN_MESSAGE_INSTALL_MODULES_DISABLED_CONTACT_US')), 0, 0, 'warning'); |
||||
1237 | } else { |
||||
1238 | $message = info_admin($langs->trans('InstallModuleFromWebHasBeenDisabledContactUs'), 0, 0, 'warning'); |
||||
1239 | } |
||||
1240 | } else { |
||||
1241 | // Show technical message |
||||
1242 | $message = info_admin($langs->trans("InstallModuleFromWebHasBeenDisabledByFile", $dolibarrdataroot . '/installmodules.lock'), 0, 0, 'warning'); |
||||
1243 | } |
||||
1244 | $allowfromweb = 0; |
||||
1245 | } |
||||
1246 | |||||
1247 | print $deschelp; |
||||
1248 | |||||
1249 | if ($allowfromweb < 1) { |
||||
1250 | print $langs->trans("SomethingMakeInstallFromWebNotPossible"); |
||||
1251 | print $message; |
||||
1252 | //print $langs->trans("SomethingMakeInstallFromWebNotPossible2"); |
||||
1253 | print '<br>'; |
||||
1254 | } |
||||
1255 | |||||
1256 | print '<br>'; |
||||
1257 | |||||
1258 | // $allowfromweb = -1 if installation or setup not correct, 0 if not allowed, 1 if allowed |
||||
1259 | if ($allowfromweb >= 0) { |
||||
1260 | if ($allowfromweb == 1) { |
||||
1261 | //print $langs->trans("ThisIsProcessToFollow").'<br>'; |
||||
1262 | } else { |
||||
1263 | print $langs->trans("ThisIsAlternativeProcessToFollow") . '<br>'; |
||||
1264 | print '<b>' . $langs->trans("StepNb", 1) . '</b>: '; |
||||
1265 | print str_replace('{s1}', $fullurl, $langs->trans("FindPackageFromWebSite", '{s1}')) . '<br>'; |
||||
1266 | print '<b>' . $langs->trans("StepNb", 2) . '</b>: '; |
||||
1267 | print str_replace('{s1}', $fullurl, $langs->trans("DownloadPackageFromWebSite", '{s1}')) . '<br>'; |
||||
1268 | print '<b>' . $langs->trans("StepNb", 3) . '</b>: '; |
||||
1269 | } |
||||
1270 | |||||
1271 | if ($allowfromweb == 1) { |
||||
1272 | print '<form enctype="multipart/form-data" method="POST" class="noborder" action="' . $_SERVER["PHP_SELF"] . '" name="forminstall">'; |
||||
1273 | print '<input type="hidden" name="token" value="' . newToken() . '">'; |
||||
1274 | print '<input type="hidden" name="action" value="install">'; |
||||
1275 | print '<input type="hidden" name="mode" value="deploy">'; |
||||
1276 | |||||
1277 | print $langs->trans("YouCanSubmitFile") . '<br><br>'; |
||||
1278 | |||||
1279 | $max = getDolGlobalString('MAIN_UPLOAD_DOC'); // In Kb |
||||
1280 | $maxphp = @ini_get('upload_max_filesize'); // In unknown |
||||
1281 | if (preg_match('/k$/i', $maxphp)) { |
||||
1282 | $maxphp = preg_replace('/k$/i', '', $maxphp); |
||||
1283 | $maxphp *= 1; |
||||
1284 | } |
||||
1285 | if (preg_match('/m$/i', $maxphp)) { |
||||
1286 | $maxphp = preg_replace('/m$/i', '', $maxphp); |
||||
1287 | $maxphp *= 1024; |
||||
1288 | } |
||||
1289 | if (preg_match('/g$/i', $maxphp)) { |
||||
1290 | $maxphp = preg_replace('/g$/i', '', $maxphp); |
||||
1291 | $maxphp *= 1024 * 1024; |
||||
1292 | } |
||||
1293 | if (preg_match('/t$/i', $maxphp)) { |
||||
1294 | $maxphp = preg_replace('/t$/i', '', $maxphp); |
||||
1295 | $maxphp *= 1024 * 1024 * 1024; |
||||
1296 | } |
||||
1297 | $maxphp2 = @ini_get('post_max_size'); // In unknown |
||||
1298 | if (preg_match('/k$/i', $maxphp2)) { |
||||
1299 | $maxphp2 = preg_replace('/k$/i', '', $maxphp2); |
||||
1300 | $maxphp2 *= 1; |
||||
1301 | } |
||||
1302 | if (preg_match('/m$/i', $maxphp2)) { |
||||
1303 | $maxphp2 = preg_replace('/m$/i', '', $maxphp2); |
||||
1304 | $maxphp2 *= 1024; |
||||
1305 | } |
||||
1306 | if (preg_match('/g$/i', $maxphp2)) { |
||||
1307 | $maxphp2 = preg_replace('/g$/i', '', $maxphp2); |
||||
1308 | $maxphp2 *= 1024 * 1024; |
||||
1309 | } |
||||
1310 | if (preg_match('/t$/i', $maxphp2)) { |
||||
1311 | $maxphp2 = preg_replace('/t$/i', '', $maxphp2); |
||||
1312 | $maxphp2 *= 1024 * 1024 * 1024; |
||||
1313 | } |
||||
1314 | // Now $max and $maxphp and $maxphp2 are in Kb |
||||
1315 | $maxmin = $max; |
||||
1316 | $maxphptoshow = $maxphptoshowparam = ''; |
||||
1317 | if ($maxphp > 0) { |
||||
1318 | $maxmin = min($max, $maxphp); |
||||
1319 | $maxphptoshow = $maxphp; |
||||
1320 | $maxphptoshowparam = 'upload_max_filesize'; |
||||
1321 | } |
||||
1322 | if ($maxphp2 > 0) { |
||||
1323 | $maxmin = min($max, $maxphp2); |
||||
1324 | if ($maxphp2 < $maxphp) { |
||||
1325 | $maxphptoshow = $maxphp2; |
||||
1326 | $maxphptoshowparam = 'post_max_size'; |
||||
1327 | } |
||||
1328 | } |
||||
1329 | |||||
1330 | if ($maxmin > 0) { |
||||
1331 | print '<script type="text/javascript"> |
||||
1332 | $(document).ready(function() { |
||||
1333 | jQuery("#fileinstall").on("change", function() { |
||||
1334 | if(this.files[0].size > ' . ($maxmin * 1024) . ') { |
||||
1335 | alert("' . dol_escape_js($langs->trans("ErrorFileSizeTooLarge")) . '"); |
||||
1336 | this.value = ""; |
||||
1337 | } |
||||
1338 | }); |
||||
1339 | }); |
||||
1340 | </script>' . "\n"; |
||||
1341 | // MAX_FILE_SIZE doit précéder le champ input de type file |
||||
1342 | print '<input type="hidden" name="MAX_FILE_SIZE" value="' . ($maxmin * 1024) . '">'; |
||||
1343 | } |
||||
1344 | |||||
1345 | print '<input class="flat minwidth400" type="file" name="fileinstall" id="fileinstall"> '; |
||||
1346 | |||||
1347 | print '<input type="submit" name="send" value="' . dol_escape_htmltag($langs->trans("Upload")) . '" class="button small">'; |
||||
1348 | |||||
1349 | if (getDolGlobalString('MAIN_UPLOAD_DOC')) { |
||||
1350 | if ($user->admin) { |
||||
1351 | $langs->load('other'); |
||||
1352 | print ' '; |
||||
1353 | print info_admin($langs->trans("ThisLimitIsDefinedInSetup", $max, $maxphptoshow, $maxphptoshowparam), 1); |
||||
1354 | } |
||||
1355 | } else { |
||||
1356 | print ' (' . $langs->trans("UploadDisabled") . ')'; |
||||
1357 | } |
||||
1358 | |||||
1359 | print '</form>'; |
||||
1360 | |||||
1361 | print '<br>'; |
||||
1362 | print '<br>'; |
||||
1363 | |||||
1364 | print '<div class="center"><div class="logo_setup"></div></div>'; |
||||
1365 | } else { |
||||
1366 | print $langs->trans("UnpackPackageInModulesRoot", $dirins) . '<br>'; |
||||
1367 | print '<b>' . $langs->trans("StepNb", 4) . '</b>: '; |
||||
1368 | print $langs->trans("SetupIsReadyForUse", constant('BASE_URL') . '/admin/modules.php?mainmenu=home', $langs->transnoentitiesnoconv("Home") . ' - ' . $langs->transnoentitiesnoconv("Setup") . ' - ' . $langs->transnoentitiesnoconv("Modules")) . '<br>'; |
||||
1369 | } |
||||
1370 | } |
||||
1371 | |||||
1372 | if (!empty($result['return'])) { |
||||
1373 | print '<br>'; |
||||
1374 | |||||
1375 | foreach ($result['return'] as $value) { |
||||
1376 | echo $value . '<br>'; |
||||
1377 | } |
||||
1378 | } |
||||
1379 | |||||
1380 | print dol_get_fiche_end(); |
||||
1381 | } |
||||
1382 | |||||
1383 | if ($mode == 'develop') { |
||||
1384 | print dol_get_fiche_head($head, $mode, '', -1); |
||||
1385 | |||||
1386 | print $deschelp; |
||||
1387 | |||||
1388 | print '<br>'; |
||||
1389 | |||||
1390 | // Marketplace |
||||
1391 | print '<table summary="list_of_modules" class="noborder centpercent">' . "\n"; |
||||
1392 | print '<tr class="liste_titre">' . "\n"; |
||||
1393 | //print '<td>'.$langs->trans("Logo").'</td>'; |
||||
1394 | print '<td colspan="2">' . $langs->trans("DevelopYourModuleDesc") . '</td>'; |
||||
1395 | print '<td>' . $langs->trans("URL") . '</td>'; |
||||
1396 | print '</tr>'; |
||||
1397 | |||||
1398 | print '<tr class="oddeven" height="80">' . "\n"; |
||||
1399 | print '<td class="center">'; |
||||
1400 | print '<div class="imgmaxheight50 logo_setup"></div>'; |
||||
1401 | print '</td>'; |
||||
1402 | print '<td>' . $langs->trans("TryToUseTheModuleBuilder", $langs->transnoentitiesnoconv("ModuleBuilder")) . '</td>'; |
||||
1403 | print '<td class="maxwidth300">'; |
||||
1404 | if (isModEnabled('modulebuilder')) { |
||||
1405 | print $langs->trans("SeeTopRightMenu"); |
||||
1406 | } else { |
||||
1407 | print '<span class="opacitymedium">' . $langs->trans("ModuleMustBeEnabledFirst", $langs->transnoentitiesnoconv("ModuleBuilder")) . '</span>'; |
||||
1408 | } |
||||
1409 | print '</td>'; |
||||
1410 | print '</tr>'; |
||||
1411 | |||||
1412 | print '<tr class="oddeven" height="80">' . "\n"; |
||||
1413 | $url = 'https://partners.dolibarr.org'; |
||||
1414 | print '<td class="center">'; |
||||
1415 | // TODO: Design logo for preferred partner (Gold partner, perhaps?) |
||||
1416 | print'<a href="' . $url . '" target="_blank" rel="noopener noreferrer external"><img border="0" class="imgautosize imgmaxwidth180" src="' . constant('DOL_URL_ROOT') . '/theme/alxarafe_shop.png"></a>'; |
||||
1417 | print '</td>'; |
||||
1418 | print '<td>' . $langs->trans("DoliPartnersDesc") . '</td>'; |
||||
1419 | print '<td><a href="' . $url . '" target="_blank" rel="noopener noreferrer external">'; |
||||
1420 | print img_picto('', 'url', 'class="pictofixedwidth"'); |
||||
1421 | print $url . '</a></td>'; |
||||
1422 | print '</tr>'; |
||||
1423 | |||||
1424 | print "</table>\n"; |
||||
1425 | |||||
1426 | print dol_get_fiche_end(); |
||||
1427 | } |
||||
1428 | |||||
1429 | // End of page |
||||
1430 | ViewMain::llxFooter(); |
||||
1431 | $db->close(); |
||||
1432 |
If you suppress an error, we recommend checking for the error condition explicitly: