PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/core/modules/DolibarrModules.class.php

https://bitbucket.org/speedealing/speedealing
PHP | 1371 lines | 893 code | 207 blank | 271 comment | 233 complexity | 0bf0557833059ac6ac8b5f8c71cefe38 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* Copyright (C) 2003-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
  4. * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
  5. * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
  6. * Copyright (C) 2005-2012 Laurent Destailleur <eldy@users.sourceforge.net>
  7. * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@capnetworks.com>
  8. * Copyright (C) 2011-2012 Herve Prot <herve.prot@symeos.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22. */
  23. /**
  24. * \file htdocs/core/modules/DolibarrModules.class.php
  25. * \brief Fichier de description et activation des modules Dolibarr
  26. */
  27. require_once DOL_DOCUMENT_ROOT . '/core/class/extrafields.class.php';
  28. /**
  29. * \class DolibarrModules
  30. * \brief Classe mere des classes de description et activation des modules Dolibarr
  31. */
  32. class DolibarrModules extends nosqlDocument {
  33. //! Database handler
  34. var $db;
  35. //! Relative path to module style sheet
  36. var $style_sheet = ''; // deprecated
  37. //! Path to create when module activated
  38. var $dirs = array();
  39. //! Tableau des boites
  40. var $boxes;
  41. //! Tableau des constantes
  42. var $const;
  43. //! Tableau des droits
  44. var $rights;
  45. //! Tableau des menus
  46. var $menu = array();
  47. //! Module parts array
  48. var $module_parts = array();
  49. //! Tableau des documents ???
  50. var $docs;
  51. var $global; // Load global from database
  52. var $dbversion = "-";
  53. function __construct($db = null) {
  54. global $couch, $conf;
  55. parent::__construct($db);
  56. //$this->useDatabase($conf->Couchdb->name);
  57. $this->useDatabase("system");
  58. /* try {
  59. $this->global = $couch->getDoc("const", true);
  60. } catch (Exception $e) {
  61. dol_print_error('', "Error : no const document in database" . $e->getMessage());
  62. } */
  63. $this->global = $conf->global;
  64. $fk_extrafields = new ExtraFields($db);
  65. $this->fk_extrafields = $fk_extrafields->load("extrafields:DolibarrModules", true); // load and cache
  66. }
  67. /**
  68. * Fonction d'activation. Insere en base les constantes et boites du module
  69. *
  70. * @param array $array_sql Array of SQL requests to execute when enabling module
  71. * @param string $options Options when enabling module ('', 'noboxes')
  72. * @return int 1 if OK, 0 if KO
  73. */
  74. function _init($array_sql = '', $options = '') {
  75. global $langs;
  76. $err = 0;
  77. $this->db->begin();
  78. // Insert activation module constant
  79. if (!$err)
  80. $err+=$this->_active();
  81. // Insert new pages for tabs into llx_const
  82. if (!$err)
  83. $err+=$this->insert_tabs();
  84. // Insert activation of module's parts
  85. if (!$err)
  86. $err+=$this->insert_module_parts();
  87. // Insert constant defined by modules, into llx_const
  88. if (!$err)
  89. $err+=$this->insert_const();
  90. // Insere les boites dans llx_boxes_def
  91. if (!$err && $options != 'noboxes')
  92. $err+=$this->insert_boxes();
  93. // Insert permission definitions of module into llx_rights_def. If user is admin, grant this permission to user.
  94. if (!$err)
  95. $err+=$this->insert_permissions(1);
  96. // Insert specific menus entries into database
  97. if (!$err)
  98. $err+=$this->insert_menus();
  99. // Create module's directories
  100. if (!$err)
  101. $err+=$this->create_dirs();
  102. // Execute addons requests
  103. $num = count($array_sql);
  104. for ($i = 0; $i < $num; $i++) {
  105. if (!$err) {
  106. $val = $array_sql[$i];
  107. $sql = '';
  108. $ignoreerror = 0;
  109. if (is_array($val)) {
  110. $sql = $val['sql'];
  111. $ignoreerror = $val['ignoreerror'];
  112. } else {
  113. $sql = $val;
  114. }
  115. dol_syslog(get_class($this) . "::_init ignoreerror=" . $ignoreerror . " sql=" . $sql, LOG_DEBUG);
  116. $result = $this->db->query($sql);
  117. if (!$result) {
  118. if (!$ignoreerror) {
  119. $this->error = $this->db->lasterror();
  120. dol_syslog(get_class($this) . "::_init Error " . $this->error, LOG_ERR);
  121. $err++;
  122. } else {
  123. dol_syslog(get_class($this) . "::_init Warning " . $this->db->lasterror(), LOG_WARNING);
  124. }
  125. }
  126. }
  127. }
  128. // Return code
  129. if (!$err) {
  130. $this->db->commit();
  131. //print_r($this->global);exit;
  132. $this->couchdb->storeDoc($this->global);
  133. $this->flush(); // clear cache
  134. return 1;
  135. } else {
  136. $this->db->rollback();
  137. return 0;
  138. }
  139. }
  140. /**
  141. * Fonction de desactivation. Supprime de la base les constantes et boites du module
  142. *
  143. * @param array $array_sql Array of SQL requests to execute when disable module
  144. * @param string $options Options when disabling module ('', 'noboxes')
  145. * @return int 1 if OK, 0 if KO
  146. */
  147. function _remove($array_sql = '', $options = '') {
  148. global $langs;
  149. $err = 0;
  150. $this->db->begin();
  151. // Remove activation module line (constant MAIN_MODULE_MYMODULE in llx_const)
  152. if (!$err)
  153. $err+=$this->_unactive();
  154. // Remove activation of module's new tabs (MAIN_MODULE_MYMODULE_TABS_XXX in llx_const)
  155. if (!$err)
  156. $err+=$this->delete_tabs();
  157. // Remove activation of module's parts (MAIN_MODULE_MYMODULE_XXX in llx_const)
  158. if (!$err)
  159. $err+=$this->delete_module_parts();
  160. // Remove constants defined by modules
  161. if (!$err)
  162. $err+=$this->delete_const();
  163. // Remove list of module's available boxes (entry in llx_boxes)
  164. if (!$err && $options != 'noboxes')
  165. $err+=$this->delete_boxes();
  166. // Remove module's permissions from list of available permissions (entries in llx_rights_def)
  167. if (!$err)
  168. $err+=$this->delete_permissions();
  169. // Remove module's menus (entries in llx_menu)
  170. if (!$err)
  171. $err+=$this->delete_menus();
  172. // Remove module's directories
  173. if (!$err)
  174. $err+=$this->delete_dirs();
  175. // Run complementary sql requests
  176. $num = count($array_sql);
  177. for ($i = 0; $i < $num; $i++) {
  178. if (!$err) {
  179. dol_syslog(get_class($this) . "::_remove sql=" . $array_sql[$i], LOG_DEBUG);
  180. $result = $this->db->query($array_sql[$i]);
  181. if (!$result) {
  182. $this->error = $this->db->error();
  183. dol_syslog(get_class($this) . "::_remove Error " . $this->error, LOG_ERR);
  184. $err++;
  185. }
  186. }
  187. }
  188. // Return code
  189. if (!$err) {
  190. $this->db->commit();
  191. //print_r($this->global);
  192. $this->couchdb->storeDoc($this->global);
  193. $this->flush(); // clear cache
  194. return 1;
  195. } else {
  196. $this->db->rollback();
  197. return 0;
  198. }
  199. }
  200. /**
  201. * Retourne le nom traduit du module si la traduction existe dans admin.lang,
  202. * sinon le nom defini par defaut dans le module.
  203. *
  204. * @return string Nom du module traduit
  205. */
  206. function getName() {
  207. global $langs;
  208. $langs->load("admin");
  209. if (empty($this->numero))
  210. $this->numero = 0;
  211. if ($langs->trans("Module" . $this->numero . "Name") != ("Module" . $this->numero . "Name")) {
  212. // Si traduction du nom du module existe
  213. return $langs->trans("Module" . $this->numero . "Name");
  214. } else {
  215. // If translation of module with its numero does not exists, we take its name
  216. return $this->name;
  217. }
  218. }
  219. /**
  220. * Retourne le nom traduit de la permssion si la traduction existe dans admin.lang,
  221. * sinon le nom defini par defaut dans le module.
  222. *
  223. * @return string Nom de la permission traduite
  224. */
  225. function getPermDesc() {
  226. global $langs;
  227. $langs->load("admin");
  228. if ($langs->trans("Permission" . $this->id) != ("Permission" . $this->id)) {
  229. // Si traduction du nom du module existe
  230. return $langs->trans("Permission" . $this->id);
  231. } else {
  232. // If translation of module with its numero does not exists, we take its name
  233. $out = $this->desc;
  234. return $out;
  235. }
  236. }
  237. /**
  238. * Retourne la description traduite du module si la traduction existe dans admin.lang,
  239. * sinon la description definie par defaut dans le module
  240. *
  241. * @return string Nom du module traduit
  242. */
  243. function getDesc() {
  244. global $langs;
  245. $langs->load("admin");
  246. if ($langs->trans("Module" . $this->numero . "Desc") != ("Module" . $this->numero . "Desc")) {
  247. // Si traduction de la description du module existe
  248. return $langs->trans("Module" . $this->numero . "Desc");
  249. } else {
  250. // Si traduction de la description du module n'existe pas, on prend definition en dur dans module
  251. return $this->description;
  252. }
  253. }
  254. /**
  255. * Retourne la version du module.
  256. * Pour les modules a l'etat 'experimental', retourne la traduction de 'experimental'
  257. * Pour les modules 'dolibarr', retourne la version de Dolibarr
  258. * Pour les autres modules, retourne la version du module
  259. *
  260. * @return string Version du module
  261. */
  262. function getVersion() {
  263. global $langs;
  264. $langs->load("admin");
  265. if ($this->version == 'experimental')
  266. return $langs->trans("VersionExperimental");
  267. elseif ($this->version == 'development')
  268. return $langs->trans("VersionDevelopment");
  269. elseif ($this->version == 'speedealing')
  270. return DOL_VERSION;
  271. elseif ($this->version == 'dolibarr')
  272. return '<span class="tag grey-gradient glossy">' . $langs->trans("In next version") . '</span>';
  273. elseif ($this->version)
  274. return $this->version;
  275. else
  276. return $langs->trans("VersionUnknown");
  277. }
  278. /**
  279. * Return list of lang files related to module
  280. *
  281. * @return array Array of lang files
  282. */
  283. function getLangFilesArray() {
  284. return $this->langfiles;
  285. }
  286. /**
  287. * Return translated label of a export dataset
  288. *
  289. * @param int $r Index of dataset
  290. * @return string Label of databaset
  291. */
  292. function getExportDatasetLabel($r) {
  293. global $langs;
  294. $langstring = "ExportDataset_" . $this->export_code[$r];
  295. if ($langs->trans($langstring) == $langstring) {
  296. // Traduction non trouvee
  297. return $langs->trans($this->export_label[$r]);
  298. } else {
  299. // Traduction trouvee
  300. return $langs->trans($langstring);
  301. }
  302. }
  303. /**
  304. * Insert constant to activate module
  305. *
  306. * @return int Nb of errors (0 if OK)
  307. */
  308. function _active() {
  309. global $conf;
  310. $err = 0;
  311. // Common module
  312. $entity = ((!empty($this->always_enabled) || !empty($this->core_enabled)) ? 0 : $conf->entity);
  313. $name = $this->const_name;
  314. $this->global->values->$name = 1;
  315. return $err;
  316. }
  317. /**
  318. * Remove activation line
  319. *
  320. * @return int Nb of errors (0 if OK)
  321. * */
  322. function _unactive() {
  323. global $conf;
  324. $name = $this->const_name;
  325. if (isset($this->global->values->$name))
  326. unset($this->global->values->$name);
  327. $err = 0;
  328. return $err;
  329. }
  330. /**
  331. * Create tables and keys required by module.
  332. * Files module.sql and module.key.sql with create table and create keys
  333. * commands must be stored in directory reldir='/module/sql/'
  334. * This function is called by this->init
  335. *
  336. * @param string $reldir Relative directory where to scan files
  337. * @return int <=0 if KO, >0 if OK
  338. */
  339. function _load_tables($reldir) {
  340. global $db, $conf;
  341. $error = 0;
  342. include_once(DOL_DOCUMENT_ROOT . "/core/lib/admin.lib.php");
  343. $ok = 1;
  344. foreach ($conf->file->dol_document_root as $dirroot) {
  345. if ($ok) {
  346. $dir = $dirroot . $reldir;
  347. $ok = 0;
  348. // Run llx_mytable.sql files
  349. $handle = @opendir($dir); // Dir may not exists
  350. if (is_resource($handle)) {
  351. while (($file = readdir($handle)) !== false) {
  352. if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_' && substr($file, 0, 4) != 'data') {
  353. $result = run_sql($dir . $file, 1, '', 1);
  354. if ($result <= 0)
  355. $error++;
  356. }
  357. }
  358. closedir($handle);
  359. }
  360. // Run llx_mytable.key.sql files (Must be done after llx_mytable.sql)
  361. $handle = @opendir($dir); // Dir may not exist
  362. if (is_resource($handle)) {
  363. while (($file = readdir($handle)) !== false) {
  364. if (preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'llx_' && substr($file, 0, 4) != 'data') {
  365. $result = run_sql($dir . $file, 1, '', 1);
  366. if ($result <= 0)
  367. $error++;
  368. }
  369. }
  370. closedir($handle);
  371. }
  372. // Run data_xxx.sql files (Must be done after llx_mytable.key.sql)
  373. $handle = @opendir($dir); // Dir may not exist
  374. if (is_resource($handle)) {
  375. while (($file = readdir($handle)) !== false) {
  376. if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 4) == 'data') {
  377. $result = run_sql($dir . $file, 1, '', 1);
  378. if ($result <= 0)
  379. $error++;
  380. }
  381. }
  382. closedir($handle);
  383. }
  384. // Run update_xxx.sql files
  385. $handle = @opendir($dir); // Dir may not exist
  386. if (is_resource($handle)) {
  387. while (($file = readdir($handle)) !== false) {
  388. if (preg_match('/\.sql$/i', $file) && !preg_match('/\.key\.sql$/i', $file) && substr($file, 0, 6) == 'update') {
  389. $result = run_sql($dir . $file, 1, '', 1);
  390. if ($result <= 0)
  391. $error++;
  392. }
  393. }
  394. closedir($handle);
  395. }
  396. if ($error == 0) {
  397. $ok = 1;
  398. }
  399. }
  400. }
  401. return $ok;
  402. }
  403. /**
  404. * Create views and documents required by module.
  405. * Files module.view.json and module.json with create view and create documents
  406. * commands must be stored in directory reldir='/module/json/'
  407. * This function is called by this->init
  408. *
  409. * @param string $reldir Relative directory where to scan files
  410. * @return int <=0 if KO, >0 if OK
  411. */
  412. function _load_documents() {
  413. global $db, $conf;
  414. $var_dbuser = array("_design/_auth");
  415. $var_dbsystem = array("_design/User", "_design/UserGroup");
  416. $list_db = $this->couchdb->listDatabases();
  417. $no_upgradeDB = array("_users", "system", "_replicator", "mips");
  418. $error = 0;
  419. $ok = 1;
  420. foreach ($conf->file->dol_document_root as $dirroot) {
  421. if ($ok) {
  422. $dir = $dirroot . "/" . strtolower($this->name) . "/json/";
  423. $ok = 0;
  424. // Create or upgrade views and documents
  425. $handle = @opendir($dir); // Dir may not exists
  426. if (is_resource($handle)) {
  427. while (($file = readdir($handle)) !== false) {
  428. if (preg_match('/\.json$/i', $file)) {
  429. $fp = fopen($dir . $file, "r");
  430. if ($fp) {
  431. $json = fread($fp, filesize($dir . $file));
  432. $obj = json_decode($json);
  433. unset($obj->_rev);
  434. //Test if document go to _users base
  435. $nbDB = 1;
  436. if (in_array($obj->_id, $var_dbuser))
  437. $this->couchdb->useDatabase("_users");
  438. else if (in_array($obj->_id, $var_dbsystem))
  439. $this->couchdb->useDatabase("system");
  440. else if (substr($obj->_id, 0, 7) == "_design")
  441. $nbDB = count($list_db);
  442. else
  443. $this->couchdb->useDatabase("system");
  444. for ($i = 0; $i < $nbDB; $i++) {
  445. if ($nbDB > 1) { //Upgrade all db
  446. if (in_array($list_db[$i], $no_upgradeDB))
  447. continue;
  448. else
  449. $this->couchdb->useDatabase($list_db[$i]);
  450. }
  451. // Test if exist document in database : upgrade
  452. try {
  453. $result = $this->couchdb->getDoc($obj->_id);
  454. $obj->_rev = $result->_rev;
  455. } catch (Exception $e) {
  456. unset($obj->_rev);
  457. }
  458. if (!empty($result)) {
  459. if ($result->class == "extrafields") {
  460. /*if (isset($obj->shortList))
  461. $obj->shortList = $result->shortList;
  462. if (isset($obj->longList))
  463. $obj->longList = $result->longList;*/
  464. foreach ($result->fields as $key => $aRow) {
  465. if ($aRow->optional) //specific extrafields
  466. $obj->fields->$key = clone $aRow;
  467. if ($aRow->enable) // Test if fields was enable or disable
  468. $obj->fields->$key->enable = true;
  469. else
  470. $obj->fields->$key->enable = false;
  471. }
  472. }
  473. }
  474. try {
  475. $this->couchdb->storeDoc($obj);
  476. $this->couchdb->useDatabase("system");
  477. } catch (Exception $e) {
  478. dol_print_error("", $e->getMessage());
  479. $error++;
  480. }
  481. }
  482. fclose($fp);
  483. }
  484. }
  485. }
  486. closedir($handle);
  487. }
  488. if ($error == 0) {
  489. $ok = 1;
  490. }
  491. }
  492. }
  493. return $ok;
  494. }
  495. /**
  496. * Insert boxes into llx_boxes_def
  497. *
  498. * @return int Nb of errors (0 if OK)
  499. */
  500. function insert_boxes() {
  501. global $conf;
  502. $err = 0;
  503. if (is_array($this->boxes)) {
  504. foreach ($this->boxes as $key => $value) {
  505. //$titre = $this->boxes[$key][0];
  506. $file = isset($this->boxes[$key][1]) ? $this->boxes[$key][1] : '';
  507. $note = isset($this->boxes[$key][2]) ? $this->boxes[$key][2] : '';
  508. $sql = "SELECT count(*) as nb FROM " . MAIN_DB_PREFIX . "boxes_def";
  509. $sql.= " WHERE file = '" . $this->db->escape($file) . "'";
  510. $sql.= " AND entity = " . $conf->entity;
  511. if ($note)
  512. $sql.=" AND note ='" . $this->db->escape($note) . "'";
  513. $result = $this->db->query($sql);
  514. if ($result) {
  515. $obj = $this->db->fetch_object($result);
  516. if ($obj->nb == 0) {
  517. $this->db->begin();
  518. if (!$err) {
  519. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "boxes_def (file,entity,note)";
  520. $sql.= " VALUES ('" . $this->db->escape($file) . "',";
  521. $sql.= $conf->entity . ",";
  522. $sql.= $note ? "'" . $this->db->escape($note) . "'" : "null";
  523. $sql.= ")";
  524. dol_syslog(get_class($this) . "::insert_boxes sql=" . $sql);
  525. $resql = $this->db->query($sql);
  526. if (!$resql)
  527. $err++;
  528. }
  529. if (!$err) {
  530. $lastid = $this->db->last_insert_id(MAIN_DB_PREFIX . "boxes_def", "rowid");
  531. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "boxes (box_id,position,box_order,fk_user)";
  532. $sql.= " VALUES (" . $lastid . ", 0, '0', 0)";
  533. dol_syslog(get_class($this) . "::insert_boxes sql=" . $sql);
  534. $resql = $this->db->query($sql);
  535. if (!$resql)
  536. $err++;
  537. }
  538. if (!$err) {
  539. $this->db->commit();
  540. } else {
  541. $this->error = $this->db->lasterror();
  542. dol_syslog(get_class($this) . "::insert_boxes " . $this->error, LOG_ERR);
  543. $this->db->rollback();
  544. }
  545. }
  546. } else {
  547. $this->error = $this->db->lasterror();
  548. dol_syslog(get_class($this) . "::insert_boxes " . $this->error, LOG_ERR);
  549. $err++;
  550. }
  551. }
  552. }
  553. return $err;
  554. }
  555. /**
  556. * Delete boxes
  557. *
  558. * @return int Nb of errors (0 if OK)
  559. */
  560. function delete_boxes() {
  561. global $conf;
  562. $err = 0;
  563. if (is_array($this->boxes)) {
  564. foreach ($this->boxes as $key => $value) {
  565. //$titre = $this->boxes[$key][0];
  566. $file = $this->boxes[$key][1];
  567. //$note = $this->boxes[$key][2];
  568. $sql = "DELETE FROM " . MAIN_DB_PREFIX . "boxes";
  569. $sql.= " USING " . MAIN_DB_PREFIX . "boxes, " . MAIN_DB_PREFIX . "boxes_def";
  570. $sql.= " WHERE " . MAIN_DB_PREFIX . "boxes.box_id = " . MAIN_DB_PREFIX . "boxes_def.rowid";
  571. $sql.= " AND " . MAIN_DB_PREFIX . "boxes_def.file = '" . $this->db->escape($file) . "'";
  572. $sql.= " AND " . MAIN_DB_PREFIX . "boxes_def.entity = " . $conf->entity;
  573. dol_syslog(get_class($this) . "::delete_boxes sql=" . $sql);
  574. $resql = $this->db->query($sql);
  575. if (!$resql) {
  576. $this->error = $this->db->lasterror();
  577. dol_syslog(get_class($this) . "::delete_boxes " . $this->error, LOG_ERR);
  578. $err++;
  579. }
  580. $sql = "DELETE FROM " . MAIN_DB_PREFIX . "boxes_def";
  581. $sql.= " WHERE file = '" . $this->db->escape($file) . "'";
  582. $sql.= " AND entity = " . $conf->entity;
  583. dol_syslog(get_class($this) . "::delete_boxes sql=" . $sql);
  584. $resql = $this->db->query($sql);
  585. if (!$resql) {
  586. $this->error = $this->db->lasterror();
  587. dol_syslog(get_class($this) . "::delete_boxes " . $this->error, LOG_ERR);
  588. $err++;
  589. }
  590. }
  591. }
  592. return $err;
  593. }
  594. /**
  595. * Remove links to new module page present in llx_const
  596. *
  597. * @return int Nb of errors (0 if OK)
  598. */
  599. function delete_tabs() {
  600. global $conf;
  601. $name = $this->const_name . "_TABS";
  602. if (count($this->global->values)) {
  603. foreach ($this->global->values as $key => $aRow) {
  604. if (strpos($key, $name) != false)
  605. if (isset($this->global->values->$key))
  606. unset($this->global->values->$key);
  607. }
  608. }
  609. $err = 0;
  610. return $err;
  611. }
  612. /**
  613. * Add links of new pages from modules in llx_const
  614. *
  615. * @return int Number of errors (0 if ok)
  616. */
  617. function insert_tabs() {
  618. global $conf;
  619. $err = 0;
  620. if (!empty($this->tabs)) {
  621. $i = 0;
  622. foreach ($this->tabs as $key => $value) {
  623. if ($value) {
  624. $name = $this->const_name . "_TABS_" . $i;
  625. $this->global->values->$name = $value;
  626. $i++;
  627. }
  628. }
  629. }
  630. return $err;
  631. }
  632. /**
  633. * Insert constants defined into $this->const array into table llx_const
  634. *
  635. * @return int Number of errors (0 if OK)
  636. */
  637. function insert_const() {
  638. global $conf;
  639. $err = 0;
  640. foreach ($this->const as $key => $value) {
  641. $name = $this->const[$key][0];
  642. $type = $this->const[$key][1];
  643. $val = $this->const[$key][2];
  644. $note = isset($this->const[$key][3]) ? $this->const[$key][3] : '';
  645. $visible = isset($this->const[$key][4]) ? $this->const[$key][4] : 0;
  646. $entity = (!empty($this->const[$key][5]) && $this->const[$key][5] != 'current') ? 0 : $conf->entity;
  647. // Clean
  648. if (empty($visible))
  649. $visible = '0';
  650. if (empty($val))
  651. $val = '';
  652. $sql = "SELECT count(*)";
  653. $sql.= " FROM " . MAIN_DB_PREFIX . "const";
  654. $sql.= " WHERE " . $this->db->decrypt('name') . " = '" . $name . "'";
  655. $sql.= " AND entity = " . $entity;
  656. $result = $this->db->query($sql);
  657. if ($result) {
  658. $row = $this->db->fetch_row($result);
  659. if ($row[0] == 0) { // If not found
  660. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "const (name,type,value,note,visible,entity)";
  661. $sql.= " VALUES (";
  662. $sql.= $this->db->encrypt($name, 1);
  663. $sql.= ",'" . $type . "'";
  664. $sql.= "," . ($val ? $this->db->encrypt($val, 1) : "''");
  665. $sql.= "," . ($note ? "'" . $this->db->escape($note) . "'" : "null");
  666. $sql.= ",'" . $visible . "'";
  667. $sql.= "," . $entity;
  668. $sql.= ")";
  669. dol_syslog(get_class($this) . "::insert_const sql=" . $sql);
  670. if (!$this->db->query($sql)) {
  671. dol_syslog(get_class($this) . "::insert_const " . $this->db->lasterror(), LOG_ERR);
  672. $err++;
  673. }
  674. } else {
  675. dol_syslog(get_class($this) . "::insert_const constant '" . $name . "' already exists", LOG_WARNING);
  676. }
  677. } else {
  678. $err++;
  679. }
  680. }
  681. return $err;
  682. }
  683. /**
  684. * Remove constants with tags deleteonunactive
  685. *
  686. * @return int <0 if KO, 0 if OK
  687. */
  688. function delete_const() {
  689. global $conf;
  690. $err = 0;
  691. foreach ($this->const as $key => $value) {
  692. $name = $this->const[$key][0];
  693. $deleteonunactive = (!empty($this->const[$key][6])) ? 1 : 0;
  694. if ($deleteonunactive) {
  695. if (isset($this->global->values->$name))
  696. unset($this->global->values->$name);
  697. }
  698. }
  699. return $err;
  700. }
  701. /**
  702. * Insert permissions definitions related to the module into llx_rights_def
  703. *
  704. * @param int $reinitadminperms If 1, we also grant them to all admin users
  705. * @return int Number of error (0 if OK)
  706. */
  707. function insert_permissions($reinitadminperms = 0) {
  708. global $conf, $user;
  709. $err = 0;
  710. //print $this->rights_class." ".count($this->rights)."<br>";
  711. // Test if module is activated
  712. $sql_del = "SELECT " . $this->db->decrypt('value') . " as value";
  713. $sql_del.= " FROM " . MAIN_DB_PREFIX . "const";
  714. $sql_del.= " WHERE " . $this->db->decrypt('name') . " = '" . $this->const_name . "'";
  715. $sql_del.= " AND entity IN (0," . $conf->entity . ")";
  716. dol_syslog(get_class($this) . "::insert_permissions sql=" . $sql_del);
  717. $resql = $this->db->query($sql_del);
  718. if ($resql) {
  719. $obj = $this->db->fetch_object($resql);
  720. if ($obj->value) {
  721. // Si module actif
  722. foreach ($this->rights as $key => $value) {
  723. $r_id = $this->rights[$key][0];
  724. $r_desc = $this->rights[$key][1];
  725. $r_type = isset($this->rights[$key][2]) ? $this->rights[$key][2] : '';
  726. $r_def = $this->rights[$key][3];
  727. $r_perms = $this->rights[$key][4];
  728. $r_subperms = isset($this->rights[$key][5]) ? $this->rights[$key][5] : '';
  729. $r_modul = $this->rights_class;
  730. if (empty($r_type))
  731. $r_type = 'w';
  732. if (dol_strlen($r_perms)) {
  733. if (dol_strlen($r_subperms)) {
  734. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "rights_def";
  735. $sql.= " (id, entity, libelle, module, type, bydefault, perms, subperms)";
  736. $sql.= " VALUES ";
  737. $sql.= "(" . $r_id . "," . $conf->entity . ",'" . $this->db->escape($r_desc) . "','" . $r_modul . "','" . $r_type . "'," . $r_def . ",'" . $r_perms . "','" . $r_subperms . "')";
  738. } else {
  739. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "rights_def";
  740. $sql.= " (id, entity, libelle, module, type, bydefault, perms)";
  741. $sql.= " VALUES ";
  742. $sql.= "(" . $r_id . "," . $conf->entity . ",'" . $this->db->escape($r_desc) . "','" . $r_modul . "','" . $r_type . "'," . $r_def . ",'" . $r_perms . "')";
  743. }
  744. } else {
  745. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "rights_def ";
  746. $sql .= " (id, entity, libelle, module, type, bydefault)";
  747. $sql .= " VALUES ";
  748. $sql .= "(" . $r_id . "," . $conf->entity . ",'" . $this->db->escape($r_desc) . "','" . $r_modul . "','" . $r_type . "'," . $r_def . ")";
  749. }
  750. dol_syslog(get_class($this) . "::insert_permissions sql=" . $sql, LOG_DEBUG);
  751. $resqlinsert = $this->db->query($sql, 1);
  752. if (!$resqlinsert) {
  753. if ($this->db->errno() != "DB_ERROR_RECORD_ALREADY_EXISTS") {
  754. $this->error = $this->db->lasterror();
  755. dol_syslog(get_class($this) . "::insert_permissions error " . $this->error, LOG_ERR);
  756. $err++;
  757. break;
  758. }
  759. else
  760. dol_syslog(get_class($this) . "::insert_permissions record already exists", LOG_INFO);
  761. }
  762. $this->db->free($resqlinsert);
  763. // If we want to init permissions on admin users
  764. if ($reinitadminperms) {
  765. include_once(DOL_DOCUMENT_ROOT . '/user/class/user.class.php');
  766. $sql = "SELECT rowid from " . MAIN_DB_PREFIX . "user where admin = 1";
  767. dol_syslog(get_class($this) . "::insert_permissions Search all admin users sql=" . $sql);
  768. $resqlseladmin = $this->db->query($sql, 1);
  769. if ($resqlseladmin) {
  770. $num = $this->db->num_rows($resqlseladmin);
  771. $i = 0;
  772. while ($i < $num) {
  773. $obj2 = $this->db->fetch_object($resqlseladmin);
  774. dol_syslog(get_class($this) . "::insert_permissions Add permission to user id=" . $obj2->rowid);
  775. $tmpuser = new User($this->db);
  776. $tmpuser->fetch($obj2->rowid);
  777. $tmpuser->addrights($r_id);
  778. $i++;
  779. }
  780. if (!empty($user->admin)) { // Reload permission for current user if defined
  781. // We reload permissions
  782. $user->clearrights();
  783. $user->getrights();
  784. }
  785. }
  786. else
  787. dol_print_error($this->db);
  788. }
  789. }
  790. }
  791. $this->db->free($resql);
  792. }
  793. else {
  794. $this->error = $this->db->lasterror();
  795. dol_syslog(get_class($this) . "::insert_permissions " . $this->error, LOG_ERR);
  796. $err++;
  797. }
  798. return $err;
  799. }
  800. /**
  801. * Delete permissions
  802. *
  803. * @return int Nb of errors (0 if OK)
  804. */
  805. function delete_permissions() {
  806. global $conf;
  807. $err = 0;
  808. $sql = "DELETE FROM " . MAIN_DB_PREFIX . "rights_def";
  809. $sql.= " WHERE module = '" . $this->rights_class . "'";
  810. $sql.= " AND entity = " . $conf->entity;
  811. dol_syslog(get_class($this) . "::delete_permissions sql=" . $sql);
  812. if (!$this->db->query($sql)) {
  813. $this->error = $this->db->lasterror();
  814. dol_syslog(get_class($this) . "::delete_permissions " . $this->error, LOG_ERR);
  815. $err++;
  816. }
  817. return $err;
  818. }
  819. /**
  820. * Insert menus entries found into $this->menu into llx_menu*
  821. *
  822. * @return int Nb of errors (0 if OK)
  823. */
  824. function insert_menus() {
  825. global $user;
  826. require_once(DOL_DOCUMENT_ROOT . "/core/class/menubase.class.php");
  827. $err = 0;
  828. if (count($this->menu) == 0)
  829. return 0;
  830. $menus = array();
  831. //var_dump($this->menu); exit;
  832. foreach ($this->menu as $value) {
  833. $id = $value['_id'];
  834. $menu[$id]->module = $this->rights_class;
  835. if (empty($value['_id'])) {
  836. $error = "ErrorBadDefinitionOfMenuArrayInModuleDescriptor (bad value for _id)";
  837. dol_print_error("", $error);
  838. $err++;
  839. }
  840. if ($value['type'] != "top" && !empty($value['fk_menu'])) {
  841. if (empty($menu[$value['fk_menu']])) {
  842. try {
  843. $this->couchdb->getDoc($value['fk_menu']);
  844. } catch (Exception $e) {
  845. $error = "ErrorBadDefinitionOfMenuArrayInModuleDescriptor (bad value for key fk_menu)";
  846. $error.="<br>Something weird happened: " . $e->getMessage() . " (errcode=" . $e->getCode() . ")\n";
  847. dol_print_error("", $error);
  848. $err++;
  849. }
  850. }
  851. }
  852. $menu[$id]->class = "menu";
  853. $menu[$id]->type = $value['type'];
  854. $menu[$id]->title = $value['titre'];
  855. $menu[$id]->url = $value['url'];
  856. $menu[$id]->langs = $value['langs'];
  857. $menu[$id]->position = (int) $value['position'];
  858. $menu[$id]->perms = $value['perms'];
  859. $menu[$id]->target = $value['target'];
  860. $menu[$id]->user = $value['user'];
  861. $menu[$id]->enabled = isset($value['enabled']) ? $value['enabled'] : false;
  862. if ($value['fk_menu'])
  863. $menu[$id]->fk_menu = $value['fk_menu'];
  864. $menu[$id]->_id = $value['_id'];
  865. // for update
  866. try {
  867. $obj = $this->couchdb->getDoc($id);
  868. $menu[$id]->_rev = $obj->_rev;
  869. } catch (Exception $e) {
  870. }
  871. }
  872. //print_r($menu);exit;
  873. if (!$err) {
  874. try {
  875. $this->couchdb->clean($menu);
  876. $this->couchdb->storeDocs($menu, false);
  877. } catch (Exception $e) {
  878. $error = "Something weird happened: " . $e->getMessage() . " (errcode=" . $e->getCode() . ")\n";
  879. dol_print_error("", $error);
  880. exit(1);
  881. }
  882. } else {
  883. dol_syslog(get_class($this) . "::insert_menus " . $this->error, LOG_ERR);
  884. }
  885. return $err;
  886. }
  887. /**
  888. * Remove menus entries
  889. *
  890. * @return int Nb of errors (0 if OK)
  891. */
  892. function delete_menus() {
  893. $err = 0;
  894. foreach ($this->menu as $key => $value) {
  895. try {
  896. $menu = $this->couchdb->getDoc($value['_id']);
  897. $menu->enabled = false;
  898. $this->couchdb->storeDoc($menu);
  899. } catch (Exception $e) {
  900. }
  901. }
  902. return $err;
  903. }
  904. /**
  905. * Create directories required by module
  906. *
  907. * @return int Nb of errors (0 if OK)
  908. */
  909. function create_dirs() {
  910. global $langs, $conf;
  911. $err = 0;
  912. if (is_array($this->dirs)) {
  913. foreach ($this->dirs as $key => $value) {
  914. $addtodatabase = 0;
  915. if (!is_array($value))
  916. $dir = $value; // Default simple mode
  917. else {
  918. $constname = $this->const_name . "_DIR_";
  919. $dir = $this->dirs[$key][1];
  920. $addtodatabase = empty($this->dirs[$key][2]) ? '' : $this->dirs[$key][2]; // Create constante in llx_const
  921. $subname = empty($this->dirs[$key][3]) ? '' : strtoupper($this->dirs[$key][3]); // Add submodule name (ex: $conf->module->submodule->dir_output)
  922. $forcename = empty($this->dirs[$key][4]) ? '' : strtoupper($this->dirs[$key][4]); // Change the module name if different
  923. if ($forcename)
  924. $constname = 'MAIN_MODULE_' . $forcename . "_DIR_";
  925. if ($subname)
  926. $constname = $constname . $subname . "_";
  927. $name = $constname . strtoupper($this->dirs[$key][0]);
  928. }
  929. // Define directory full path ($dir must start with "/")
  930. if (empty($conf->global->MAIN_MODULE_MULTICOMPANY) || $conf->entity == 1)
  931. $fulldir = DOL_DATA_ROOT . $dir;
  932. else
  933. $fulldir = DOL_DATA_ROOT . "/" . $conf->entity . $dir;
  934. // Create dir if it does not exists
  935. if ($fulldir && !file_exists($fulldir)) {
  936. if (dol_mkdir($fulldir) < 0) {
  937. $this->error = $langs->trans("ErrorCanNotCreateDir", $fulldir);
  938. dol_syslog(get_class($this) . "::_init " . $this->error, LOG_ERR);
  939. $err++;
  940. }
  941. }
  942. // Define the constant in database if requested (not the default mode)
  943. if ($addtodatabase) {
  944. $result = $this->insert_dirs($name, $dir);
  945. if ($result)
  946. $err++;
  947. }
  948. }
  949. }
  950. return $err;
  951. }
  952. /**
  953. * Insert directories in llx_const
  954. *
  955. * @param string $name Name
  956. * @param string $dir Directory
  957. * @return int Nb of errors (0 if OK)
  958. */
  959. function insert_dirs($name, $dir) {
  960. global $conf;
  961. $err = 0;
  962. $sql = "SELECT count(*)";
  963. $sql.= " FROM " . MAIN_DB_PREFIX . "const";
  964. $sql.= " WHERE " . $this->db->decrypt('name') . " = '" . $name . "'";
  965. $sql.= " AND entity = " . $conf->entity;
  966. dol_syslog(get_class($this) . "::insert_dirs sql=" . $sql);
  967. $result = $this->db->query($sql);
  968. if ($result) {
  969. $row = $this->db->fetch_row($result);
  970. if ($row[0] == 0) {
  971. $sql = "INSERT INTO " . MAIN_DB_PREFIX . "const (name,type,value,note,visible,entity)";
  972. $sql.= " VALUES (" . $this->db->encrypt($name, 1) . ",'chaine'," . $this->db->encrypt($dir, 1) . ",'Directory for module " . $this->name . "','0'," . $conf->entity . ")";
  973. dol_syslog(get_class($this) . "::insert_dirs sql=" . $sql);
  974. $resql = $this->db->query($sql);
  975. }
  976. } else {
  977. $this->error = $this->db->lasterror();
  978. dol_syslog(get_class($this) . "::insert_dirs " . $this->error, LOG_ERR);
  979. $err++;
  980. }
  981. return $err;
  982. }
  983. /**
  984. * Remove directory entries
  985. *
  986. * @return int Nb of errors (0 if OK)
  987. */
  988. function delete_dirs() {
  989. global $conf;
  990. $err = 0;
  991. $sql = "DELETE FROM " . MAIN_DB_PREFIX . "const";
  992. $sql.= " WHERE " . $this->db->decrypt('name') . " like '" . $this->const_name . "_DIR_%'";
  993. $sql.= " AND entity = " . $conf->entity;
  994. dol_syslog(get_class($this) . "::delete_dirs sql=" . $sql);
  995. if (!$this->db->query($sql)) {
  996. $this->error = $this->db->lasterror();
  997. dol_syslog(get_class($this) . "::delete_dirs " . $this->error, LOG_ERR);
  998. $err++;
  999. }
  1000. return $err;
  1001. }
  1002. /**
  1003. * Insert activation of generic parts from modules in llx_const
  1004. *
  1005. * @return int Nb of errors (0 if OK)
  1006. */
  1007. function insert_module_parts() {
  1008. global $conf;
  1009. $error = 0;
  1010. $entity = $conf->entity;
  1011. if (is_array($this->module_parts) && !empty($this->module_parts)) {
  1012. foreach ($this->module_parts as $key => $value) {
  1013. $newvalue = $value;
  1014. // Serialize array parameters
  1015. if (is_array($value)) {
  1016. // Can defined other parameters
  1017. if (is_array($value['data']) && !empty($value['data'])) {
  1018. $newvalue = json_encode($value['data']);
  1019. if (isset($value['entity']))
  1020. $entity = $value['entity'];
  1021. }
  1022. else {
  1023. $newvalue = json_encode($value);
  1024. }
  1025. }
  1026. $name = $this->const_name . "_" . strtoupper($key);
  1027. $this->global->values->$name = $newvalue;
  1028. }
  1029. }
  1030. return $error;
  1031. }
  1032. /**
  1033. * Remove activation of generic parts of modules from llx_const
  1034. *
  1035. * @return int Nb of errors (0 if OK)
  1036. */
  1037. function delete_module_parts() {
  1038. global $conf;
  1039. $err = 0;
  1040. $entity = $conf->entity;
  1041. if (is_array($this->module_parts) && !empty($this->module_parts)) {
  1042. foreach ($this->module_parts as $key => $value) {
  1043. // If entity is defined
  1044. if (is_array($value) && isset($value['entity']))
  1045. $entity = $value['entity'];
  1046. $name = $this->const_name . "_" . strtoupper($key);
  1047. foreach ($this->global->values as $key => $aRow) {
  1048. if (strpos($key, $name) != false)
  1049. unset($this->global->values->$key);
  1050. }
  1051. }
  1052. }
  1053. return $err;
  1054. }
  1055. /**
  1056. * Return modules configurations
  1057. */
  1058. function load_modules_files(&$filename, &$modules, &$orders, &$categ, &$dirmod, &$modNameLoaded) {
  1059. global $conf;
  1060. // Search modules dirs
  1061. $excludes = array('admin', 'conf', 'includes', 'install', 'langs', 'man', 'public', 'theme');
  1062. foreach ($conf->file->dol_document_root as $type => $dirroot) {
  1063. $handle = @opendir($dirroot);
  1064. if (is_resource($handle)) {
  1065. while (($file = readdir($handle)) !== false) {
  1066. if (is_dir($dirroot . '/' . $file) && substr($file, 0, 1) <> '.' && !in_array($file, $excludes)) {
  1067. $dir = $dirroot . '/' . $file . '/core/modules/';
  1068. if ($file == 'core')
  1069. $dir = $dirroot . '/' . $file . '/modules/';
  1070. if (is_dir($dir)) {
  1071. $filehandle = @opendir($dir);
  1072. if (is_resource($filehandle)) {
  1073. while (($file = readdir($filehandle)) !== false) {
  1074. //print "$i ".$file."\n<br>";
  1075. if (is_readable($dir . $file) && substr($file, 0, 3) == 'mod' && substr($file, dol_strlen($file) - 10) == '.class.php') {
  1076. $modName = substr($file, 0, dol_strlen($file) - 10);
  1077. if ($modName) {
  1078. if (!empty($modNameLoaded[$modName])) {
  1079. $mesg = "Error: Module " . $modName . " was found twice: Into " . $modNameLoaded[$modName] . " and " . $dir . ". You probably have an old file on your disk.<br>";
  1080. error_log($mesg);
  1081. continue;
  1082. }
  1083. try {
  1084. $res = include_once($dir . $file);
  1085. $objMod = new $modName($this->db); // TODO remove $this->db
  1086. $modNameLoaded[$modName] = $dir;
  1087. if ($objMod->numero >= 0) {
  1088. $j = $objMod->numero;
  1089. } else {
  1090. $j = 1000 + $i;
  1091. }
  1092. $modulequalified = 1;
  1093. // We discard modules according to features level (PS: if module is activated we always show it)
  1094. $const_name = 'MAIN_MODULE_' . strtoupper(preg_replace('/^mod/i', '', get_class($objMod)));
  1095. if ($objMod->version == 'development' && $conf->global->MAIN_FEATURES_LEVEL < 2 && !$conf->global->$const_name)
  1096. $modulequalified = 0;
  1097. if ($objMod->version == 'experimental' && $conf->global->MAIN_FEATURES_LEVEL < 1 && !$conf->global->$const_name)
  1098. $modulequalified = 0;
  1099. if ($modulequalified) {
  1100. $modules[$j] = $objMod;
  1101. $filename[$j] = $modName;
  1102. $orders[$j] = $objMod->family . "_" . $j; // Tri par famille puis numero module
  1103. //print "x".$modName." ".$orders[$i]."\n<br>";
  1104. if (isset($categ[$objMod->special]))
  1105. $categ[$objMod->special]++; // Array of all different modules categories
  1106. else
  1107. $categ[$objMod->special] = 1;
  1108. $dirmod[$j] = $dir;
  1109. $j++;
  1110. $i++;
  1111. }
  1112. else
  1113. error_log("Module " . get_class($objMod) . " not qualified");
  1114. } catch (Exception $e) {
  1115. error_log("Failed to load " . $dir . $file . " " . $e->getMessage());
  1116. }
  1117. }
  1118. }
  1119. }
  1120. closedir($filehandle);
  1121. } else {
  1122. error_log("htdocs/admin/modules.php: Failed to open directory " . $dir . ". See permission and open_basedir option.");
  1123. }
  1124. }
  1125. }
  1126. }
  1127. closedir($handle);
  1128. }
  1129. }
  1130. asort($orders);
  1131. return $mesg;
  1132. }
  1133. /**
  1134. * Upgrade specific file for database not a a module : For the core
  1135. */
  1136. function upgradeCore() {
  1137. $files = array("DolibarrModules.view", "MenuAuguria.view", "Dict.view", "extrafields.DolibarrModules");
  1138. $dir = DOL_DOCUMENT_ROOT . "/install/couchdb/json/";
  1139. foreach ($files as $row) {
  1140. $fp = fopen($dir . $row . ".json", "r");
  1141. if ($fp) {
  1142. $json = fread($fp, filesize($dir . $row . ".json"));
  1143. $obj = json_decode($json);
  1144. unset($obj->_rev);
  1145. } else {
  1146. print "file not found : " . $dir . $row . ".json";
  1147. exit;
  1148. }
  1149. try {
  1150. $result = $this->couchdb->getDoc($obj->_id);
  1151. $obj->_rev = $result->_rev;
  1152. } catch (Exception $e) {
  1153. }
  1154. try {
  1155. $this->couchdb->storeDoc($obj);
  1156. } catch (Exception $e) {
  1157. print $row;
  1158. print $e->getMessage();
  1159. exit;
  1160. }
  1161. }
  1162. }
  1163. }
  1164. ?>