Эх сурвалжийг харах

Maj core + fix + marque blanche

idleman 3 жил өмнө
parent
commit
53bd33f7d1
100 өөрчлөгдсөн 1969 нэмэгдсэн , 1731 устгасан
  1. 0 2
      .gitignore
  2. 0 3
      .htaccess
  3. 1 1
      account.api.php
  4. 2 2
      account.global.php
  5. 1 1
      account.lost.php
  6. 223 195
      action.php
  7. 421 0
      api.php
  8. 1 0
      class/Api.class.php
  9. 3 3
      class/ContactPerson.class.php
  10. 124 0
      class/Dictionary.class.php
  11. 1 1
      class/Entity.class.php
  12. 20 20
      class/FieldType.class.php
  13. 16 6
      class/File.class.php
  14. 1 1
      class/JWToken.class.php
  15. 22 3
      class/Plugin.class.php
  16. 1 1
      class/User.class.php
  17. 19 17
      common.php
  18. 3 3
      constant-sample.php
  19. 25 18
      css/component.css
  20. 10 3
      css/main.css
  21. 0 0
      disabled.maintenance
  22. 8 8
      footer.php
  23. 11 1
      function.php
  24. 1 1
      header.php
  25. 3 0
      install.php
  26. 40 35
      js/component.js
  27. 38 35
      js/filter.component.js
  28. 131 118
      js/main.js
  29. 3 3
      js/plugins.js
  30. 2 2
      js/vendor/trumbowyg.plugins.js
  31. 2 2
      maintenance.php
  32. 9 0
      migration/migration.php
  33. 2 3
      plugin/activedirectory/AdServer.class.php
  34. 1 1
      plugin/client/Client.class.php
  35. 18 18
      plugin/client/action.php
  36. 12 12
      plugin/client/client.plugin.php
  37. 7 7
      plugin/client/js/main.js
  38. 7 7
      plugin/client/tab.home.php
  39. 1 1
      plugin/clientmap/app.json
  40. 1 0
      plugin/contact/action.php
  41. 1 1
      plugin/contact/page.sheet.contact.person.php
  42. 277 321
      plugin/dashboard/action.php
  43. 4 5
      plugin/dashboard/dashboard.plugin.php
  44. 37 55
      plugin/directory/action.php
  45. 4 5
      plugin/directory/directory.plugin.php
  46. 5 5
      plugin/docker/Ovh.class.php
  47. 1 1
      plugin/docker/action.php
  48. 3 3
      plugin/docker/docker.plugin.php
  49. 1 1
      plugin/docker/setting.global.docker.php
  50. 1 1
      plugin/docker/tab.environment.migration.php
  51. 2 4
      plugin/document/Element.class.php
  52. 1 0
      plugin/document/WebDav.class.php
  53. 105 90
      plugin/document/js/document.api.js
  54. 3 3
      plugin/dynamicform/DynamicField.class.php
  55. 9 8
      plugin/dynamicform/DynamicForm.class.php
  56. 1 1
      plugin/dynamicform/app.json
  57. 2 2
      plugin/dynamicform/dynamicform.plugin.php
  58. 6 1
      plugin/employee/Employee.class.php
  59. 4 4
      plugin/employee/EmployeeContract.class.php
  60. 1 1
      plugin/employee/EmployeeWorkTime.class.php
  61. 1 1
      plugin/employee/action.php
  62. 5 3
      plugin/employee/page.list.employee.php
  63. 1 1
      plugin/employee/page.sheet.employee.php
  64. 1 1
      plugin/example/ContactExample.class.php
  65. 4 4
      plugin/example/action.php
  66. 1 1
      plugin/example/app.json
  67. 29 35
      plugin/example/example.plugin.php
  68. 1 1
      plugin/example/page.list.contact.php
  69. 7 7
      plugin/example/page.sheet.contact.php
  70. 44 43
      plugin/export/action.php
  71. 2 5
      plugin/export/export.plugin.php
  72. 27 27
      plugin/factory/action.php
  73. 4 7
      plugin/factory/factory.plugin.php
  74. 4 4
      plugin/factory/template/Erp plugin/action.php
  75. 2 2
      plugin/factory/template/Erp plugin/page.list.{{entity.readable}}.php
  76. 16 16
      plugin/factory/template/Erp plugin/{{plugin}}.plugin.php
  77. 0 30
      plugin/factory/template/Test template/list.php
  78. 0 22
      plugin/factory/template/Wordpress plugin/action.php
  79. 0 1
      plugin/factory/template/Wordpress plugin/css/main.css
  80. 0 6
      plugin/factory/template/Wordpress plugin/functions.php
  81. 0 51
      plugin/factory/template/Wordpress plugin/js/main.js
  82. 0 254
      plugin/factory/template/Wordpress plugin/sys1.{{plugin}}.php
  83. 0 18
      plugin/factory/template/Wordpress plugin/{{Entity}}.class.php
  84. 1 1
      plugin/glpi/Glpi.class.php
  85. 23 31
      plugin/glpi/action.php
  86. 5 6
      plugin/glpi/glpi.plugin.php
  87. 1 1
      plugin/host/Machine.class.php
  88. 2 2
      plugin/host/action.php
  89. 1 1
      plugin/host/app.json
  90. 14 14
      plugin/host/host.plugin.php
  91. 1 1
      plugin/host/page.sheet.machine.php
  92. 1 1
      plugin/host/setting.global.host.php
  93. 1 1
      plugin/import/action.php
  94. 8 8
      plugin/import/import.plugin.php
  95. 3 3
      plugin/import/js/main.js
  96. 2 2
      plugin/import/template/CsvImport.class.php
  97. 57 60
      plugin/issue/action.php
  98. 4 5
      plugin/issue/issue.plugin.php
  99. 31 5
      plugin/navigation/MenuItem.class.php
  100. 6 3
      plugin/navigation/navigation.plugin.php

+ 0 - 2
.gitignore

@@ -1,10 +1,8 @@
 /constant.php
-/plugin/enabled.json
 /plugin/demo/*
 /file/*/
 /db/*.db
 /sql.debug.sql
-*.maintenance
 *.sublime-project
 *.sublime-workspace
 /plugin/document/logs/*.*

+ 0 - 3
.htaccess

@@ -25,9 +25,6 @@ RewriteEngine On
   Require all denied
 </Files>
 
-RewriteRule ^api/(.*)$ action.php?action=api&command=$1 [QSA]
-
-
 #if requested resource isn't a file
 # and isn't a directory
 # then serve local error script 

+ 1 - 1
account.api.php

@@ -18,7 +18,7 @@ if(empty($api_id)){
 ?>
 <div id="account-api-form" class="account-api-form">
 	<br>
-	<div onclick="account_api_save()" class="btn btn-success float-right"><i class="fas fa-check"></i> Enregistrer</div>
+	<div onclick="core_account_api_save()" class="btn btn-success float-right"><i class="fas fa-check"></i> Enregistrer</div>
 	<h3>API & TOKEN</h3>
 	<div class="clear"></div>
 	<hr>

+ 2 - 2
account.global.php

@@ -4,14 +4,14 @@ if (!$myUser->connected()) throw new Exception("Vous devez être connecté pour
 ?>
 <div id="user-form" class="user-form">
 	<br>
-	<div onclick="account_save()" class="btn btn-success float-right"><i class="fas fa-check"></i> Enregistrer</div>
+	<div onclick="core_account_save()" class="btn btn-success float-right"><i class="fas fa-check"></i> Enregistrer</div>
 	<h3><?php echo $myUser->fullName(); ?> <small class="text-muted">(<?php echo $myUser->login; ?>)</small></h3>
 	<div class="clear"></div>
 	<hr>
 	<div class="row">
 		<div class="col-md-6">
 			<label for="avatar">Photo :</label><br/>
-			<input id="avatar" data-type="image" name="avatar" class="form-control-file" value="<?php echo $myUser->getAvatar(); ?>" type="file" data-delete="account_avatar_delete(this)" data-default-src="img/default-avatar.png">
+			<input id="avatar" data-type="image" name="avatar" class="form-control-file" value="<?php echo $myUser->getAvatar(); ?>" type="file" data-delete="core_account_avatar_delete(this)" data-default-src="img/default-avatar.png">
 		</div>
 		<div class="col-md-6">
 			<div class="user-ranks">

+ 1 - 1
account.lost.php

@@ -66,7 +66,7 @@ if(isset($_['token'])){
 			<div class="col-xl-6 col-lg-8">
 				<span class="d-block w-100 mb-1"><i class="far fa-fw fa-envelope mr-1"></i><small class="text-muted">Adresse e-mail du compte :</small></span>
 				<input class="form-control m-auto text-center" placeholder="email@email.com" type="text" id="mail">
-				<div class="btn btn-primary w-100 mt-2" id="lost-password-send" onclick="account_lost_password(this);"><i class="far fa-envelope-open"></i> Récupérer</div>
+				<div class="btn btn-primary w-100 mt-2" id="lost-password-send" onclick="core_account_lost_password(this);"><i class="far fa-envelope-open"></i> Récupérer</div>
 			</div>
 		<?php endif; ?>
 		</div>

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 223 - 195
action.php


+ 421 - 0
api.php

@@ -0,0 +1,421 @@
+<?php
+/* CORE API */
+	//Infos api
+	$api = new Api("core", "Api du coeur applicatif");
+	$api->route('infos','retourne les informations sur l\'environnement','GET',function($request,&$response){
+		global $myUser,$databases_credentials;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+
+		$repository = '';
+		if(file_exists(__DIR__.SLASH.'.git'.SLASH.'config')){
+			$stream = file_get_contents(__DIR__.SLASH.'.git'.SLASH.'config');
+			preg_match('|url = (.*\.fr)[:/]([^\n]*)|is', $stream,$match);
+			$repository = $match[2];
+			$repositoryUrl = preg_replace('|[^@]*@|i','http://',$match[1]).'/'.$match[2];
+		}
+		if(file_exists(__DIR__.SLASH.'.git'.SLASH.'refs'.SLASH.'heads'.SLASH.'master'))
+			$commitVersion = str_replace(array("\n","\r"),"",file_get_contents(__DIR__.SLASH.'.git'.SLASH.'refs'.SLASH.'heads'.SLASH.'master'));
+
+		$response['application']['label'] = PROGRAM_NAME;
+		$response['application']['version'] = SOURCE_VERSION;
+		$response['application']['versionning']['type'] = 'git';
+		$response['application']['versionning']['repository'] = $repository;
+		$response['application']['versionning']['repository_url'] = $repositoryUrl;
+		$response['application']['versionning']['commit_version'] = $commitVersion;
+		$response['application']['timezone'] = TIME_ZONE;
+		$response['php']['version'] = phpversion();
+		$response['apache']['version'] = apache_get_version();
+		$response['databases'] = array();
+		foreach ($databases_credentials as $key => $value) {
+			unset($value['password']);
+			$value['uid'] = $key;
+			$response['databases'][] = $value;
+		}
+
+		$response['os']['type'] = PHP_OS;
+		$response['os']['time'] = time();
+
+	});
+
+
+	$api->route('token','retourne un jwt token en fonction des identifiants fournis sur l\'environnement','POST',function($request,&$response){
+
+		$_ = json_decode($request['body'],true);
+
+		if(!isset($_['api_id']) || !isset($_['api_secret']))  throw new Exception("Api Credentials are missing",401);
+		global $conf;
+		if(empty($conf->get('jwtauth_secret'))) throw new Exception('JWT secret is missing in core',501);
+
+		if(session_status() == PHP_SESSION_ACTIVE) session_destroy();
+		session_start();
+
+		$apiKey = UserPreference::load(array('key'=>'api_id','value'=>encrypt($_['api_id'])));
+		if(!$apiKey) throw new Exception('Api id not found',404);
+
+		$apiSecret = UserPreference::load(array('key'=>'api_secret','user'=>$apiKey->user,'value'=>encrypt($_['api_secret'])));
+		if(!$apiSecret) throw new Exception('Bad api secret',401);
+
+		$apiEnabled = UserPreference::load(array('key'=>'api_enabled','user'=>$apiKey->user,'value'=>1));
+		if(!$apiEnabled) throw new Exception('Api is not enabled for this account',401);
+
+		global $myUser,$myFirm;
+		$myUser = User::connectLogin($apiSecret->user);
+
+		if(!$myUser || !$myUser->connected()) throw new Exception('Bad credentials',401);
+		if(file_exists('enabled.maintenance') && $myUser->superadmin != 1) throw new Exception('Maintenance is enabled, only super admin can connects',403);
+
+		$_SESSION['currentUser'] = serialize($myUser);
+		$_SESSION['firm'] = serialize($myFirm);
+
+		$response['session'] = session_id();
+
+		$json = array();
+		$json['exp'] = strtotime('+8hours');
+
+		$json['attributes'] = array(
+			'session_id' => session_id(),
+			'user' => $myUser->login
+		);
+		$response['token'] = JWToken::createFromJson($json,$conf->get('jwtauth_secret'));
+
+	});
+
+
+
+	//right api
+	$api->route('rights','retourne la liste des droits du logiciel','GET',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['rights'] = array();
+
+		if(isset($request['parameters']['sort']))  throw new Exception("Sort is not implemented for firms",501);
+		if(isset($request['parameters']['filter']))  throw new Exception("Filter is not implemented for firms",501);
+
+		$limit = isset($request['parameters']['limit']) ? array($request['parameters']['limit']) : array();
+
+		foreach (Right::loadAll(array(),array(),$limit) as $right) {
+			$row = $right->toArray();
+			$response['rights'][] = $row;
+		}
+	});
+
+	$api->route('rights/[rightid]','ajoute/modifie un droit du logiciel','PUT',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['right'] = array();
+		//Création
+		$_ = $request['parameters'];
+		$form = json_decode($request['body'],true);
+		if(!$form) throw new Exception("Invalid JSON body",400);
+		User::check_access('right','edit');
+
+		if(!empty($request['pathes'])){
+			$right = Right::getById($request['pathes'][0]);
+			if(empty($right->id)) throw new Exception("Right not found", 404);
+			$response['code'] = 200; //Modifié
+		}else{
+			$right =  new right();
+			if(!isset($form['rank']) || empty($form['rank'])) throw new Exception("L'id du rang est obligatoire",400);
+			if(!isset($form['scope']) || empty($form['scope'])) throw new Exception("Le nom de la scope est obligatoire",400);
+			if(!isset($form['firm']) || empty($form['firm'])) throw new Exception("L'id de l'établissement est obligatoire",400);
+
+			$response['code'] = 201; //Créé
+		}
+
+		//Check si le rang existe
+		$rank = Rank::getById($form['rank']);
+		if(empty($rank->id)) throw new Exception("Rank not found", 400);
+
+		//Check si la firm existe
+		$firm = Firm::getById($form['firm']);
+		if(empty($firm->id)) throw new Exception("Firm not found", 400);
+
+		//Check si la scope existe
+		$scopes = array();
+		Plugin::callHook('section',array(&$scopes));
+		$find = false;
+		foreach($scopes as $scope=>$description){
+			if ($scope==$form['scope']){
+				$find = true;
+				break;
+			}
+		}
+		if (!$find) throw new Exception("Section not found", 400);
+
+		if(isset($form['targetUid'])) $right->targetUid = $form['targetUid'];
+		if(isset($form['scope'])) $right->scope = $form['scope'];
+		if(isset($form['firm'])) $right->firm = $form['firm'];
+		if(isset($form['read'])) $right->read = $form['read'];
+		if(isset($form['edit'])) $right->edit = $form['edit'];
+		if(isset($form['delete'])) $right->delete = $form['delete'];
+		if(isset($form['configure'])) $right->configure = $form['configure'];
+
+		$right->save();
+		Log::put("Création/Modification de droit ".$right->toText(),'Droit');
+		$response['right'] = array('id'=>$right->id,'scope'=>$right->scope);
+
+	});
+
+	$api->route('rights/rightid','Supprime un rang du logiciel','DELETE',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		if(empty($request['pathes'])) throw new Exception("You must specify right id", 400);
+		User::check_access('right','delete');
+		$right = Right::getById($request['pathes'][0]);
+		if(!$right) throw new Exception("Right not found",404);
+
+		$right->deleteById($right->id);
+
+		Log::put("Suppression du rang ".$right->toText(),'Rang');
+		$response['code'] = 204;
+	});
+
+	//rank api
+	$api->route('ranks','retourne la liste des rangs du logiciel','GET',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['ranks'] = array();
+
+		if(isset($request['parameters']['sort']))  throw new Exception("Sort is not implemented for firms",501);
+		if(isset($request['parameters']['filter']))  throw new Exception("Filter is not implemented for firms",501);
+
+		$limit = isset($request['parameters']['limit']) ? array($request['parameters']['limit']) : array();
+		foreach (Rank::loadAll(array(),array(),$limit) as $rank) {
+			$row = $rank->toArray();
+			$response['ranks'][] = $row;
+		}
+	});
+
+	$api->route('ranks/[rankid]','ajoute/modifie un rang du logiciel','PUT',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['rank'] = array();
+		//Création
+		$_ = $request['parameters'];
+		$form = json_decode($request['body'],true);
+		if(!$form) throw new Exception("Invalid JSON body",400);
+		User::check_access('rank','edit');
+
+		if(!empty($request['pathes'])){
+			$rank = Rank::getById($request['pathes'][0]);
+			if(empty($rank->id)) throw new Exception("Rank not found", 404);
+			$response['code'] = 200; //Modifié
+		}else{
+			$rank =  new rank();
+			if(!isset($form['label']) || empty($form['label'])) throw new Exception("Le libellé est obligatoire",400);
+			//Check si un rang n'existe pas déjà avec ce label
+			if(Rank::load(array('label'=>$form['label']))) throw new Exception("Un rang existe déjà avec ce nom",400);
+			$rank->label = $form['label'];
+			$response['code'] = 201; //Créé
+		}
+
+		if(isset($form['label'])) $rank->label = $form['label'];
+		if(isset($form['description'])) $rank->description = $form['description'];
+
+		$rank->save();
+		Log::put("Création/Modification de rang ".$rank->toText(),'Rang');
+		$response['rank'] = array('id'=>$rank->id,'label'=>$rank->label);
+
+	});
+
+	$api->route('ranks/rankid','Supprime un rang du logiciel','DELETE',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		if(empty($request['pathes'])) throw new Exception("You must specify rank id", 400);
+		User::check_access('rank','delete');
+		$rank = Rank::getById($request['pathes'][0]);
+		if(!$rank) throw new Exception("Rank not found",404);
+
+		foreach(UserFirmRank::loadAll(array('rank'=>$rank->id)) as $ufrLink)
+			UserFirmRank::deleteById($ufrLink->id);
+
+		$rank->deleteById($rank->id);
+
+		Log::put("Suppression du rang ".$rank->toText(),'Rang');
+		$response['code'] = 204;
+	});
+
+
+
+	//firm api
+	$api->route('firms','retourne la liste des établissements du logiciel','GET',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['firms'] = array();
+
+		if(isset($request['parameters']['sort']))  throw new Exception("Sort is not implemented for firms",501);
+		if(isset($request['parameters']['filter']))  throw new Exception("Filter is not implemented for firms",501);
+
+		$limit = isset($request['parameters']['limit']) ? array($request['parameters']['limit']) : array();
+
+		foreach (Firm::loadAll(array(),array(),$limit) as $i=>$firm) {
+			$row = $firm->toArray();
+			$response['firms'][] = $row;
+		}
+	});
+
+	$api->route('firms/[firmid]','ajoute/modifie un établissement du logiciel','PUT',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['firm'] = array();
+		//Création
+		$_ = $request['parameters'];
+		$form = json_decode($request['body'],true);
+		if(!$form) throw new Exception("Invalid JSON body",400);
+		User::check_access('firm','edit');
+
+		if(!empty($request['pathes'])){
+			$firm = Firm::getById($request['pathes'][0]);
+			if(empty($firm->id)) throw new Exception("Firm not found", 404);
+			$response['code'] = 200; //Modifié
+		}else{
+			$firm =  new Firm();
+			if(!isset($form['label']) || empty($form['label'])) throw new Exception("Le libellé est obligatoire",400);
+			if(!isset($form['mail']) || empty($form['mail'])) throw new Exception('Le champ "Mail"est obligatoire',400);
+			//Check si une firm n'existe pas déjà avec ce label
+			if(Firm::load(array('label'=>$form['label']))) throw new Exception("Un établissement existe déjà avec ce nom",400);
+			$firm->label = $form['label'];
+			$response['code'] = 201; //Créé
+		}
+
+		if(isset($form['label'])) $firm->label = $form['label'];
+		if(isset($form['description'])) $firm->description = $form['description'];
+		if(isset($form['mail'])) $firm->mail = $form['mail'];
+		if(isset($form['phone'])) $firm->phone = $form['phone'];
+		if(isset($form['fax'])) $firm->fax = $form['fax'];
+		if(isset($form['street'])) $firm->street = $form['street'];
+		if(isset($form['street2'])) $firm->street2 = $form['street2'];
+		if(isset($form['city'])) $firm->city = $form['city'];
+		if(isset($form['zipcode'])) $firm->zipcode = $form['zipcode'];
+		if(isset($form['siret'])) $firm->siret = $form['siret'];
+		if(isset($form['iban'])) $firm->iban = $form['iban'];
+
+		$firm->save();
+		Log::put("Création/Modification de l'établissement ".$firm->toText(),'Etablissement');
+		$response['firm'] = array('id'=>$firm->id,'label'=>$firm->label);
+
+	});
+
+	$api->route('firms/firmid','Supprime un établissement du logiciel','DELETE',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		if(empty($request['pathes'])) throw new Exception("You must specify firm id", 400);
+		User::check_access('firm','delete');
+		$firm = Firm::getById($request['pathes'][0]);
+		if(!$firm) throw new Exception("Firm not found",404);
+
+		foreach(UserFirmRank::loadAll(array('firm'=>$firm->id)) as $ufrLink)
+			UserFirmRank::deleteById($ufrLink->id);
+
+		$firm->deleteById($firm->id);
+
+		Log::put("Suppression de l'établissement ".$firm->toText(),'Etablissement');
+		$response['code'] = 204;
+	});
+
+	//user api
+	$api->route('account','retourne les informations du compte connecté','GET',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['account'] = $myUser->toArray();
+		unset($response['account']['password']);
+	});
+
+	//user api
+	$api->route('users','retourne la liste des utilisateurs du logiciel','GET',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['users'] = array();
+
+		if(isset($request['parameters']['sort']))  throw new Exception("Sort is not implemented for users",501);
+		if(isset($request['parameters']['filter']))  throw new Exception("Filter is not implemented for users",501);
+
+		foreach (User::getAll(array('right'=>false)) as $i=>$user) {
+			if(isset($request['parameters']['limit']) && $request['parameters']['limit']==$i) break;
+			$row = $user->toArray();
+			unset($row['password']);
+			unset($row['manager']);
+			$row['origin'] = !isset($row['id']) ?  'plugin': 'database';
+			$response['users'][] = $row;
+		}
+	});
+
+	$api->route('users/[userid]','ajoute/modifie un utilisateur du logiciel','PUT',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		$response['user'] = array();
+		//Création
+		$_ = $request['parameters'];
+		$form = json_decode($request['body'],true);
+		if(!$form) throw new Exception("Invalid JSON body",400);
+		User::check_access('user','edit');
+
+		if(!empty($request['pathes'])){
+			$user = User::byLogin($request['pathes'][0]);
+
+			if(empty($user->login)) throw new Exception("User not found", 404);
+			$response['code'] = 200; //Modifié
+		}else{
+			$user =  new User();
+			if(!isset($form['login']) || empty($form['login'])) throw new Exception("Identifiant obligatoire",400);
+			if(!isset($form['password']) || empty($form['password'])) throw new Exception("Mot de passe obligatoire",400);
+			if(!isset($form['mail']) || empty($form['mail'])) throw new Exception('Le champ "Mail"est obligatoire',400);
+
+			foreach(User::getAll(array('right'=>false)) as $existingUser)
+				if($existingUser->mail == trim($_['mail'])) throw new Exception("Un utilisateur existe déjà avec cette adresse e-mail");
+
+			//Check si un user n'existe pas déjà avec ce login (on récupère tous les users car user peut être supprimé logiquement / désactivé uniquement)
+			if(User::load(array('login'=>$form['login']))) throw new Exception("Un utilisateur existe déjà avec cet identifiant",400);
+			$user->login = $form['login'];
+			$response['code'] = 201; //Créé
+		}
+
+		if(!empty(trim($form['password']))){
+			$passwordErrors = User::check_password_format(html_entity_decode($form['password']));
+			if(count($passwordErrors)!=0 && !$myUser->superadmin) throw new Exception("Le format de mot de passe ne respecte pas les conditions suivantes : <br>".implode("<br>",$passwordErrors), 400);
+
+			if($form['password']==$form['login'] || $form['password']==$form['mail'] ) throw new Exception("Le mot de passe ne peut pas être identique à l'identifiant ou à l'e-mail",400);
+
+			$user->password = User::password_encrypt($form['password']);
+			$user->preference('passwordTime',time());
+		}
+
+		if(isset($form['firstname'])) $user->firstname = mb_ucfirst(mb_strtolower($form['firstname']));
+		if(isset($form['name'])) $user->name = mb_strtoupper($form['name']);
+		if(isset($form['mail'])) $user->mail = $form['mail'];
+
+		$user->state = User::ACTIVE;
+		if(isset($form['manager'])) $user->manager = $form['manager'];
+		$user->save();
+		User::getAll(array('right'=>true,'force'=>true));
+		Log::put("Création/Modification de l'utilisateur ".$user->toText(),'Utilisateur');
+		$response['user'] = array('id'=>$user->id,'login'=>$user->login);
+
+	});
+
+	$api->route('users/userid','Supprime un utilisateur du logiciel','DELETE',function($request,&$response){
+		global $myUser;
+		if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
+		if(empty($request['pathes'])) throw new Exception("You must spcify user login", 400);
+		User::check_access('user','delete');
+		$user = User::byLogin($request['pathes'][0]);
+		if(!$user) throw new Exception("User not found",404);
+		if($user->superadmin == 1) throw new Exception("You can't delete superadmin account",403);
+		if($user->login == $myUser->login) throw new Exception("You can't delete your own account",403);
+		if(empty($user->id)) throw new Exception("You cant delete no db account", 400);
+
+		$user = User::getById($user->id);
+		$user->state = User::INACTIVE;
+		$user->save();
+
+		foreach(UserFirmRank::loadAll(array('user'=>$user->login)) as $ufrLink)
+			UserFirmRank::deleteById($ufrLink->id);
+		if(isset($_SESSION['users_rights'])) unset($_SESSION['users_rights']);
+		if(isset($_SESSION['users_norights'])) unset($_SESSION['users_norights']);
+		Log::put("Suppression de l'utilisateur ".$user->toText(),'Utilisateur');
+		$response['code'] = 204;
+	});
+
+	$api->register();
+	/* FIN CORE API */
+?>

+ 1 - 0
class/Api.class.php

@@ -82,6 +82,7 @@ class Api{
 	public static function run(){
 		global $_,$myUser;
 		$response = array();
+		
 		try{
 			set_error_handler(function( $errno ,  $errstr , $errfile ,  $errline){
 				throw new Exception("Error ".$errno." Processing Request : ".$errfile." => ".$errstr.' L'.$errline, 500);

+ 3 - 3
class/ContactPerson.class.php

@@ -96,9 +96,9 @@ class ContactPerson extends Entity{
 		$data = array();
 
 		$query .= 'SELECT *,';
-		$query .= '(SELECT value FROM '.Contact::tableName().' c WHERE c.type=? AND c.scope=? AND c.uid={{table}}.id AND c.label=? LIMIT 1) as phone';
-		$query .= ',(SELECT value FROM '.Contact::tableName().' c WHERE c.type=? AND c.scope=? AND c.uid={{table}}.id AND c.label=? LIMIT 1) as mobile';
-		$query .= ',(SELECT value FROM '.Contact::tableName().' c WHERE c.type=? AND c.scope=? AND c.uid={{table}}.id AND c.label=? LIMIT 1) as mail';
+		$query .= '(SELECT value FROM '.Contact::tableName().' c WHERE c.type=? AND c.scope=? AND c.uid={{table}}.id AND (c.label=? OR c.label IS NULL) LIMIT 1) as phone';
+		$query .= ',(SELECT value FROM '.Contact::tableName().' c WHERE c.type=? AND c.scope=? AND c.uid={{table}}.id AND (c.label=? OR c.label IS NULL) LIMIT 1) as mobile';
+		$query .= ',(SELECT value FROM '.Contact::tableName().' c WHERE c.type=? AND c.scope=? AND c.uid={{table}}.id AND (c.label=? OR c.label IS NULL) LIMIT 1) as mail';
 		$query .= ' FROM {{table}}';
 		
 		$data[] = Contact::PHONE;

+ 124 - 0
class/Dictionary.class.php

@@ -0,0 +1,124 @@
+<?php
+/**
+* Manage application and plugins lists with key/value pair.
+* 
+* @author valentin carruesco
+*
+* @category Core
+*
+* @license copyright
+*/
+class Dictionary extends Entity {
+	public $id,$slug,$label,$parent,$state,$sublistlabel,$childs;
+	public $entityLabel = 'Liste configurable';
+	protected $fields = array(
+		'id' => array('label'=>'Identifiant', 'type' => 'key'),
+		'slug' => array('label'=>'Identifiant lisible', 'type'=>'text'),
+		'label' => array('label'=>'Libellé', 'type' => 'text'),
+		'parent' => array('label'=>'ID liste parente', 'type'=>'integer'),
+		'state' => array('label'=>'État', 'type'=>'text'),
+		'sublistlabel' => array('label'=>'Libellé de la sous liste', 'type'=>'textarea')
+	);
+
+	public function __construct() {
+		parent::__construct();
+	}
+
+	public function toArray($decoded=false) {
+		$array = parent::toArray();
+		$array['childs'] = $this->childs;
+		return $array;
+	}
+
+	//Retourne une liste formatée en fonction de son slug
+	//(retourne ses enfants si le parametre childs est à true)
+	public static function slugToArray($slug, $childs = false, $state = self::ACTIVE){
+		$listArray = array();
+		$lists = self::bySlug($slug, $childs, $state);
+		if(!$childs) return $lists;
+
+		foreach($lists as $list)
+			$listArray[$list->id] = $list;
+		return $listArray;
+	}
+
+	//Retourne une liste en fonction de son slug (retourne ses enfants si le parametre childs est à true)
+	public static function bySlug($slug, $childs = false, $state = self::ACTIVE){
+		if($childs) return self::childs(array('slug'=>$slug,'state:IN'=>$state));
+		return self::load(array("slug"=>$slug,'state:IN'=>$state));
+	}
+
+	public static function childs($param = array(),$options = array('depth'=>1,'format'=>'object'),$level=1) {
+		$childs = array();
+		
+		if(isset($param['id']) && $param['id']==0){
+			$parent = new Dictionary();
+			$parent->id = 0;
+			$parent->label = 'Racine';
+
+		}else{
+			$parent = self::load($param);
+		}
+		
+		if(!$parent) return $childs;
+		$state = isset($param['state:IN']) ? $param['state:IN'] : self::ACTIVE;
+		foreach (self::loadAll(array('parent'=>$parent->id, 'state:IN'=>$state), array(' label ASC ')) as $child) {
+			if($options['depth']>$level){
+				$param['id'] = $child->id;
+				$child->childs = self::childs($param,$options,$level+1);
+			}
+			$childs[] = $options['format'] == 'object' ? $child : $child->toArray();
+		}
+		return $childs;
+	}
+
+	public static function hierarchy($idOrSlug, $slug, &$elements=array()) {
+	   if(is_numeric($idOrSlug)){
+	   		$current = self::getById($idOrSlug);
+	   }else{
+	   		$current = self::bySlug($idOrSlug);
+	   }
+	  
+	   if(!$current) return array();
+
+	   if(($current->parent == 0 && $slug != '') || ($current->parent == -1 && $slug == '')) return $elements;
+
+	   //gestion du slug racine
+	   if($slug == ''){
+	   		$parent = new Dictionary();
+	   		$parent->id = 0;
+	   //gestion des slugs classiques
+	   }else{
+			$parent = self::load(array('id' => $current->parent));
+	   }
+
+
+	   $children = self::childs(array('id'=>$parent->id));
+
+	   $parent->childs = array();
+
+	   foreach($children as $child){
+
+	    	if($child->id == $current->id) {
+	    		$child = !empty($elements) ? $elements : $child;
+	    		$child->selected = true;
+	    	}else{
+	    		$child->childs = array();
+	    		$child->childs = self::childs(array('id'=>$child->id));
+	    	}
+    		$parent->childs[] = $child;
+	   }
+
+	   $elements = $parent;
+	   return self::hierarchy($parent->id, $slug, $elements);
+	}
+
+	//Supprime un dictionary et ses enfants de manières récursive
+	public static function remove($slug){
+		$childs = self::bySlug($slug,true);
+		self::delete(array('slug'=>$slug));
+		if(!is_array($childs)) return;
+		foreach ($childs as $item) 
+			self::remove($item->slug);
+	}
+}

+ 1 - 1
class/Entity.class.php

@@ -974,7 +974,7 @@ class Entity {
     }
 
     public static function logFile($msg,$backtrace=null){
-        if(strpos(ROOT_URL, '127.0.0.1') === false && strpos(ROOT_URL, 'localhost') === false ) return;
+        if(strpos(ROOT_URL, '127.0.0.1') === false && strpos(ROOT_URL, 'dev.local') === false && strpos(ROOT_URL, 'localhost') === false ) return;
         file_put_contents(__DIR__.SLASH.'..'.SLASH.'sql.debug.sql', date('H:i:s').' | '.$msg.PHP_EOL,FILE_APPEND);
         //A décommenter pour obtenir la stacktrace d'un appel sql dans le fichier sql.debug.sql
         //if(isset($backtrace)) file_put_contents(__DIR__.SLASH.'..'.SLASH.'sql.debug.sql', json_encode($backtrace,JSON_PRETTY_PRINT).PHP_EOL,FILE_APPEND);

+ 20 - 20
class/FieldType.class.php

@@ -101,7 +101,7 @@ class FieldType{
 		====================================================================================================================================================================
 		Date        |    12345       | d/m/y      | d/m/y              | d/m/y                     | <input data-type="date" ... value="{{onLoad}}">        | 12345
 		User        |    theo.lecoq  | theo.lecoq | Théo Lecoq         | Théo Lecoq                | <input data-type="user" ... value="{{onLoad}}">        | theo.lecoq
-		Dictionnary |    6           | 6          | Véhicules > bateau | Véhicules > bateau        | <input data-type="dictionnary" ... value="{{onLoad}}"> | 6
+		Dictionary |    6           | 6          | Véhicules > bateau | Véhicules > bateau        | <input data-type="dictionary" ... value="{{onLoad}}"> | 6
 		password    |    ==x$yh..    | toto       | toto               | toto                      | <input data-type="password" ... value="{{onLoad}}">    | ==x$yh..
 		url         |    http://...  | http://... | http://...         | <a href="http://..."></a> | <input data-type="url" ... value="{{onLoad}}">         | http://..
 
@@ -391,7 +391,7 @@ class FieldType{
 		$type->onHtmlDisplay = function($value,$options = array()){
 			$raw = $options['type']->onRawDisplay;
 			$html = $raw($value,$options);
-			if(isset($options['decoration']) && $options['decoration']) $html = '<img src="action.php?action=account_avatar_download&amp;user='.$value.'&amp;extension=jpg" class="avatar-mini avatar-rounded avatar-login" title="'.$html.'"> '.$html;
+			if(isset($options['decoration']) && $options['decoration']) $html = '<img src="action.php?action=core_account_avatar_download&amp;user='.$value.'&amp;extension=jpg" class="avatar-mini avatar-rounded avatar-login" title="'.$html.'"> '.$html;
 			return $html;
 		};
 		$type->icon = 'fas fa-user';
@@ -683,11 +683,11 @@ class FieldType{
 
 		//Dictionnaire
 		$type_dictionary = new self();
-		$type_dictionary->slug = 'dictionnary';
+		$type_dictionary->slug = 'dictionary';
 		$type_dictionary->label = 'Liste configurable';
 		$type_dictionary->sqlType = 'int';
 		$type_dictionary->default_attributes =  array_merge($type_text->default_attributes,array(
-			'data-type'=>'"dictionnary"',
+			'data-type'=>'"dictionary"',
 			'data-slug'=>'"{{key}}"',
 			'data-depth'=>'"1"',
 			'key'=>'data-disable-label',
@@ -696,7 +696,7 @@ class FieldType{
 		));
 		$type_dictionary->settings = array(
 			'slug'=> array(
-				'type'=>'dictionnary',
+				'type'=>'dictionary',
 				'label'=>'Liste ciblée',
 				'attributes'=> array(
 					'class'=>'"form-control"',
@@ -707,8 +707,8 @@ class FieldType{
 		);
 		$type_dictionary->onRawDisplay  = function($value,$options = array()){
 			if(empty($value) || !is_numeric($value)) return '';
-			$dictionnary = Dictionnary::getById($value);
-			return !$dictionnary? '':$dictionnary->label;
+			$dictionary = Dictionary::getById($value);
+			return !$dictionary? '':$dictionary->label;
 		};
 
 		$type_dictionary->fromRawDisplay = function($value,$options = array()){
@@ -716,8 +716,8 @@ class FieldType{
 			$filters = array('label'=>$value);
 			if(isset($options['parent'])) $filters['parent'] = $options['parent'];
 
-			$dictionnary = Dictionnary::load($filters);
-			return !$dictionnary ? 0 : $dictionnary->id;
+			$dictionary = Dictionary::load($filters);
+			return !$dictionary ? 0 : $dictionary->id;
 		};
 
 		$type_dictionary->onInput  = function($field = array(),$options = array()){
@@ -773,8 +773,8 @@ class FieldType{
 					"view" => "checkbox-list",
 					"value-separator" => ","
 				),
-				'=' =>array("view" =>'dictionnary'),
-				'!=' =>array("view" =>'dictionnary'),
+				'=' =>array("view" =>'dictionary'),
+				'!=' =>array("view" =>'dictionary'),
 				'null' =>array(),
 				'not null' =>array()
 			)
@@ -902,7 +902,7 @@ class FieldType{
 
 		$type_checkbox->settings = array(
 			'slug'=> array(
-				'type'=>'dictionnary',
+				'type'=>'dictionary',
 				'label'=>'Liste ciblée',
 				'attributes'=> array(
 					'class'=>'"form-control"',
@@ -950,8 +950,8 @@ class FieldType{
 				'inline-or' =>array(
 					"view" => "checkbox-list"
 				),
-				'=' =>array("view" =>'dictionnary'),
-				'!=' =>array("view" =>'dictionnary'),
+				'=' =>array("view" =>'dictionary'),
+				'!=' =>array("view" =>'dictionary'),
 				'null' =>array(),
 				'not null' =>array()
 			)
@@ -1001,7 +1001,7 @@ class FieldType{
 
 			$results = array();
 
-			//dictionnary
+			//dictionary
 			$ids = array();
 			foreach($values as $i=>$id){
 				if(empty($id) || !is_numeric($id)) continue;
@@ -1009,10 +1009,10 @@ class FieldType{
 				$ids[] = $id ;
 			}
 			if(count($ids)!=0){
-				$dictionnaries = Dictionnary::loadAll(array('id:IN'=>$ids));
+				$dictionnaries = Dictionary::loadAll(array('id:IN'=>$ids));
 
-				foreach($dictionnaries as $dictionnary){
-					$results[] = $dictionnary->label;
+				foreach($dictionnaries as $dictionary){
+					$results[] = $dictionary->label;
 				}
 			}
 
@@ -1044,8 +1044,8 @@ class FieldType{
 			$filters = array('label'=>$value);
 			if(isset($options['parent'])) $filters['parent'] = $options['parent'];
 
-			$dictionnary = Dictionnary::load($filters);
-			return !$dictionnary ? 0 : $dictionnary->id;
+			$dictionary = Dictionary::load($filters);
+			return !$dictionary ? 0 : $dictionary->id;
 		};
 
 		$type_checkbox->icon = 'fas fa-list';

+ 16 - 6
class/File.class.php

@@ -79,7 +79,7 @@ class File{
 		}
 	}
 
-	public static function downloadFile($path,$name=null,$mime = null,$forceDownload = null,$trimParentDir = true){
+	public static function downloadFile($path,$name=null,$mime = null,$forceDownload = null,$trimParentDir = true,$cache = true){
 		if($trimParentDir) $path = str_replace('..','',$path);
 		$hasFile = glob($path);
 		if(count($hasFile)==0) throw new Exception("Fichier inexistant :".$path);
@@ -97,12 +97,16 @@ class File{
 		if (ob_get_contents()) ob_end_clean();
 		header("Content-Type: ".$mime);
 		header("Content-Length: " . strlen($stream));
-		header('Expires: Sun, 01 Jan 2014 00:00:00 GMT');
-		header('Cache-Control: no-store, no-cache, must-revalidate');
-		header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
-		header('Cache-Control: post-check=0, pre-check=0', FALSE);
-		header('Pragma: no-cache');
 		header("Content-Disposition: ".($forceDownload?"attachment":"inline")."; filename=\"".utf8_decode($name)."\"");
+
+		if($cache){
+			header('Expires: Sun, 24 Jan 1988 00:00:00 GMT');
+			header('Cache-Control: no-store, no-cache, must-revalidate');
+			header('Cache-Control: post-check=0, pre-check=0', FALSE);
+			header('Pragma: no-cache');
+			header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+		}
+
 		echo $stream; 
 	}
 
@@ -125,6 +129,12 @@ class File{
 	public static function dir(){
 		return __ROOT__.FILE_PATH;
 	}
+
+	//Return core folder's path
+	public static function core(){
+		return self::dir().'core';
+	}
+	
 	public static function temp(){
 		$path = self::dir().SLASH.'tmp'.SLASH;
 		if(!file_exists($path)) mkdir($path,0755,true);

+ 1 - 1
class/JWToken.class.php

@@ -1,7 +1,7 @@
 <?php
 /**
  * JWToken utilities.
- * @author Administrateur SYS1
+ * @author Kiss Team
  * @category Plugin
  * @license copyright
  */

+ 22 - 3
class/Plugin.class.php

@@ -13,6 +13,25 @@ class Plugin{
 		$this->state = false;
 	}
 
+	public function toArray(){
+		return array(
+			'id' => $this->id,
+			'name' => $this->name,
+			'author' => $this->author,
+			'link' => $this->link,
+			'licence' => $this->licence,
+			'folder' => $this->folder,
+			'description' => $this->description,
+			'version' => $this->version,
+			'state' => $this->state,
+			'type' => $this->type,
+			'require' => $this->require,
+			'firms' => $this->firms,
+			'color' => $this->color,
+			'icon' => $this->icon
+		);
+	}
+
 	public static function exist($id){
 		foreach(self::getAll() as $plugin)
 			if($plugin->id==$id) return true;
@@ -31,10 +50,10 @@ class Plugin{
 	
 	public static function includeAll(){
 		global $myFirm;
-		
+		$validFirm = is_object($myFirm) && is_numeric($myFirm->id) && $myFirm->id!=-1;
 		foreach(self::getAll() as $plugin) {
 			if(!$plugin->state) continue;
-			if(is_object($myFirm) && is_numeric($myFirm->id) && $myFirm->id!=-1 && !in_array($myFirm->id, $plugin->firms)) continue;
+			if($validFirm && !in_array($myFirm->id, $plugin->firms)) continue;
 			
 			$main = $plugin->path().SLASH.$plugin->folder.'.plugin.php';
 			if(file_exists($main)) require_once($main);
@@ -141,7 +160,7 @@ class Plugin{
 	}
 	
 	public static  function states($states = false){
-		$enabledFile = __ROOT__.PLUGIN_PATH.'enabled.json';
+		$enabledFile = File::core().SLASH.'plugin.json';
 		if(!file_exists($enabledFile)) touch($enabledFile);
 		if(!is_array($states)){
 			$enabled = json_decode(file_get_contents($enabledFile),true);

+ 1 - 1
class/User.class.php

@@ -348,7 +348,7 @@ class User extends Entity {
         if(count($files)>0){
             if($getPath) return $files[0];
             preg_match("/\.(\w{3,4})$|\?/m", $files[0], $extension);
-            $avatar = 'action.php?action=account_avatar_download&user='.urlencode($this->login).'&extension='.$extension[1];
+            $avatar = 'action.php?action=core_account_avatar_download&user='.urlencode($this->login).'&extension='.$extension[1];
         }
         return $avatar;
     }

+ 19 - 17
common.php

@@ -56,18 +56,18 @@ Configuration::setting('configuration-global',array(
 	//Thème
 	"Thème",
 	"logo-light" => array("label"=>"Logo application (clair)", "legend"=>"S'appliquera sur les fonds sombre de l'ensemble des établissements", "type"=>"image"/*,"default"=>'img/logo/default-logo.png'*/, "attributes"=>array(
-		"data-action"=>"core_setting_logo",
+		"data-action"=>"core_general_logo",
 		"data-id"=>"logo-light",
 		"data-data"=>"{\"variant\":\"light\"}",
 		
 	)),
 	"logo-dark" => array("label"=>"Logo application (sombre)", "legend"=>"S'appliquera sur les fonds clairs de l'ensemble des établissements", "type"=>"image"/*, "default"=>"img/logo/default-logo.dark.png"*/, "attributes"=>array(
-		"data-action"=>"core_setting_logo",
+		"data-action"=>"core_general_logo",
 		"data-id"=>"logo-dark",
 		"data-data"=>"{\"variant\":\"dark\"}",
 	)),
 	"favicon" => array("label"=>"Favicon application", "legend"=>"Affichée dans les onglets de navigation", "type"=>"image"/*, "default"=>"img/logo/default-favicon.png"*/, "attributes"=>array(
-		"data-action"=>"core_setting_favicon",
+		"data-action"=>"core_general_favicon",
 		"data-id"=>"favicon",
 	)),
 	//Confs générales
@@ -100,7 +100,7 @@ Configuration::setting('configuration-global',array(
 	"Identifiant :",
 	'login_forbidden_char' => array("label"=>"Caractères interdits","type"=>"text","legend"=>"<small class='text-danger'> La virgule ','' est par défaut interdite pour tout identifiant</small>","placeholder"=>"e.g. <>&!?"),
 	//Mots de passe
-	'Mots de passe : <div class="btn btn-warning btn-small float-right" onclick="general_reset_password_delay()"><i class="fas fa-exclamation-triangle"></i> Forcer le renouvellement</div>',
+	'Mots de passe : <div class="btn btn-warning btn-small float-right" onclick="core_general_password_reset_delay()"><i class="fas fa-exclamation-triangle"></i> Forcer le renouvellement</div>',
 	'password_forbidden_char' => array("label"=>"Caractères interdits","type"=>"text","legend"=>"<small class='text-danger'> Aucun caractère n'est interdit par défaut </small>","placeholder"=>"e.g. <>&!?"),
 	'password_delay'=>array("label"=>"Renouvellement", "legend"=>"Forcer l'utilisateur a renouveller son mot de passe tous les X jours (laisser vide pour désactiver)", "type"=>"integer", "placeholder"=>"e.g. 30"),
 	'password_allow_lost'=>array("label"=>"Oubli de mot de passe", "legend"=>"Proposer la récuperation du mot de passe oublié", "type"=>"boolean"),
@@ -225,19 +225,10 @@ Plugin::addHook("menu_setting", function(&$settingMenu){
 			'category' => 'administration'
 		);
 
-	if($myUser->can('plugin','configure'))
-		$settingMenu[]= array(
-			'sort' =>24,
-			'url' => 'setting.php?section=firmPlugin',
-			'icon' => 'fas fa-angle-right',
-			'label' => 'Établissement / Plugins',
-			'category' => 'administration'
-		);
-
-	if($myUser->can('dictionnary','configure'))
+	if($myUser->can('dictionary','configure'))
 		$settingMenu[]= array(
 			'sort' =>20,
-			'url' => 'setting.php?section=dictionnary',
+			'url' => 'setting.php?section=dictionary',
 			'icon' => 'fas fa-angle-right',
 			'label' => 'Listes de valeur'
 		);
@@ -350,6 +341,17 @@ Preferred-Languages: fr,en
 Canonical: https://'.ROOT_URL.'/.well-known/security.txt';
 });
 
+//API handle
+Plugin::addHook("rewrite", function ($requested){
+	global $conf,$myUser,$_;
+	$requested = trim($requested, '/');
+	$directories = explode('/',$requested);
+	if(array_shift($directories) != 'api') return;
+	$_['command'] = implode('/',$directories);
+	require_once(__DIR__.SLASH."api.php");
+	Api::run();
+});
+
 //media
 Plugin::addHook("rewrite", function ($requested){
 	global $conf,$myUser;
@@ -402,7 +404,7 @@ Plugin::addHook("page", function(){
 Plugin::addHook("content_setting", function(){
 	global $_;
 	$_['section'] = !isset($_['section']) ? 'global': $_['section'];
-	if(in_array($_['section'],array('global','plugin','rank','right','user','firm','userfirmrank','firmPlugin','log','dictionnary','update')) && file_exists('setting.'.$_['section'].'.php'))
+	if(in_array($_['section'],array('global','plugin','rank','right','user','firm','userfirmrank','firmPlugin','log','dictionary','update')) && file_exists('setting.'.$_['section'].'.php'))
 		require_once('setting.'.$_['section'].'.php');
 });
 Plugin::addHook("content_account", function(){
@@ -421,7 +423,7 @@ Right::register('firm', array('label'=> 'Gestion des établissements'));
 Right::register('plugin', array('label'=> 'Gestion des plugins'));
 Right::register('rank', array('label'=> 'Gestion des rangs et droits'));
 Right::register('log', array('label'=> 'Gestion des logs programme'));
-Right::register('dictionnary', array('label'=> 'Gestion des listes programme'));
+Right::register('dictionary', array('label'=> 'Gestion des listes programme'));
 Right::register('file', array('label'=> 'Gestion des fichiers'));
 Right::register('account', array('label'=> 'Gestion du compte courant'));
 Right::register('history', array('label'=> 'Gestion des panels commentaires'));

+ 3 - 3
constant-sample.php

@@ -31,9 +31,9 @@ define('ROOT_URL','{{root}}');
 define('CRYPTKEY','{{cryptKey}}');
 //logs toutes les requetes sans formattage
 define('BASE_DEBUG',false);
-define('COOKIE_NAME','erp-core-cookie');
-define('PROGRAM_NAME','Core ERP');
-define('PROGRAM_AUTHOR','Team');
+define('COOKIE_NAME','kiss-cookie');
+define('PROGRAM_NAME','Kiss');
+define('PROGRAM_AUTHOR','Kiss Team');
 define('SOURCE_VERSION','1.0');
 
 define('ADMIN_MAIL','{{admin_mail}}');

+ 25 - 18
css/component.css

@@ -83,7 +83,7 @@ input[data-type="file"]{
     position: absolute;
     top: 0;
     width: 100%;
-    padding: 10px; 
+    padding: 10px;
     font-size: 12px;
     line-height: 25px;
     left: 0;
@@ -179,7 +179,7 @@ input[data-type="file"]{
 }
 .component-file-cover .upload-header{
     top: 0;
-    left: 0; 
+    left: 0;
     height: 100%;
     width: 100%;
     z-index: 10;
@@ -189,7 +189,7 @@ input[data-type="file"]{
     height: 100%;
     width: 100%;
     top: 0;
-    left: 0; 
+    left: 0;
     position: absolute;
 }
 .component-file-cover .upload-list,.component-file-cover .upload-list > li{
@@ -294,7 +294,7 @@ input[data-type="filepicker"] {
 .data-type-filepicker[readonly] .filepicker-clear{
     display: none;
 }
-.filepicker-modal i.far.fa-folder, 
+.filepicker-modal i.far.fa-folder,
 .filepicker-modal i.far.fa-folder-open {
     color: #f1c40f;
 }
@@ -730,6 +730,13 @@ span.data-mention-object{
     right: 5px;
     top: 10px;
 }
+.history-panel .advanced-search .filter-operator select {
+    padding-left: 0;
+}
+.history-panel .advanced-search .filter-value{
+    display: block;
+    margin-right: 0;
+}
 /* FIN COMPOSANT HISTORY */
 
 /* COMPOSANT URL  */
@@ -1038,7 +1045,7 @@ span.data-mention-object{
     border-radius: 0;
 }
 .advanced-search-box .options > div:first-child{
-    border-radius: 0 0 3px 0; 
+    border-radius: 0 0 3px 0;
 }
 .advanced-search-box .options > div:last-child{
     border-radius: 0 0 0 3px;
@@ -1088,8 +1095,8 @@ span.data-mention-object{
         padding-top: 0.35rem;
         opacity: 1;
     }
-    .advanced-search-box .filter-column, 
-    .advanced-search-box .filter-operator, 
+    .advanced-search-box .filter-column,
+    .advanced-search-box .filter-operator,
     .advanced-search-box .filter-value {
         width: 100%;
         display: block;
@@ -1100,8 +1107,8 @@ span.data-mention-object{
         padding-top: 0.25rem;
         height: calc(1.5em + .5rem + 2px);
     }
-    .advanced-search-box .filter-column select, 
-    .advanced-search-box .filter-operator select, 
+    .advanced-search-box .filter-column select,
+    .advanced-search-box .filter-operator select,
     .advanced-search-box .filter-value select {
         width: 100%;
         font-size: 0.9em;
@@ -1295,13 +1302,13 @@ div.component-icon[required]{
     border: 2px dashed #cecece;
     color:#cecece;
     border-radius: 5px;
-    padding: 5px; 
+    padding: 5px;
     transition: all 0.2s ease-in-out;
     height: 35px;
     width: 35px;
 }
-.component-icon .no-icon.dropdown-icon-item:focus, 
-.component-icon .no-icon.dropdown-icon-item:active, 
+.component-icon .no-icon.dropdown-icon-item:focus,
+.component-icon .no-icon.dropdown-icon-item:active,
 .component-icon .no-icon.dropdown-icon-item:hover {
     border-color: #ffc107;
     color: #ffc107;
@@ -1328,7 +1335,7 @@ div.component-icon[required]{
 .entitypicker-modal .plugin-list-container{
     max-height: 600px;
     overflow: auto;
-} 
+}
 input[data-type="entitypicker"]{
     display: none;
 }
@@ -1737,7 +1744,7 @@ div.data-type-user{
 div.data-type-user[disabled],div.data-type-user[readonly] {
     background-color: #e9ecef !important;
 }
-.input-group > .form-control.data-type-user, 
+.input-group > .form-control.data-type-user,
 .input-group > .form-control-plaintext.data-type-user {
     position: unset;
 }
@@ -1774,14 +1781,14 @@ div.data-type-user::-webkit-scrollbar {
   width: 5px;
 }
 div.data-type-user::-webkit-scrollbar-track {
-  background: #f1f1f1; 
+  background: #f1f1f1;
 }
 div.data-type-user::-webkit-scrollbar-thumb {
-  background: #888; 
+  background: #888;
   border-radius: 5px;
 }
 div.data-type-user::-webkit-scrollbar-thumb:hover {
-  background: #555; 
+  background: #555;
 }
 div.data-type-user[required] {
     border-left: 0.25rem solid #FFA100 !important;
@@ -2076,4 +2083,4 @@ input.data-type-firm{
     display: inline-block;
     width: auto;
 }
-/* FIN COMPOSANT IMAGE 
+/* FIN COMPOSANT IMAGE

+ 10 - 3
css/main.css

@@ -640,7 +640,7 @@ div[contenteditable="false"]{
 select.select-inline:first-of-type {
 	margin-left: 0;
 }
-.dictionnary-container select.select-control {
+.dictionary-container select.select-control {
 	margin-bottom: 10px;
 }
 div.advanced-search div.filter-value-block select.form-control.filter-value {
@@ -650,7 +650,7 @@ div.advanced-search div.filter-value-block select.form-control.filter-value {
 div.filter-box div.simple-search > div.input-group-prepend {
 	z-index: 10;
 }
-.input-group-sm .form-control[data-type="dictionnary"] {
+.input-group-sm .form-control[data-type="dictionary"] {
     height: calc(1.5em + .5rem + 2px);
 }
 .filter-box .advanced-search .filter-value {
@@ -1353,6 +1353,13 @@ code {
 .form-control.hidden{
 	display: none!important;
 }
+
+.list-style-type-none,.list-style-type-none li{
+	list-style-type: none;
+	margin: 0;
+	padding: 0;
+}
+
 .invisible,
 .form-control.invisible{
 	visibility: hidden;
@@ -1398,7 +1405,7 @@ code {
     max-width: 100%;
     margin: 1.75rem auto;
 }
-.component-dictionnary-table .action-cell{
+.component-dictionary-table .action-cell{
 	width: 90px;
 }
 .text-small{

+ 0 - 0
disabled.maintenance


+ 8 - 8
footer.php

@@ -161,7 +161,7 @@ uasort ($footerMenu , function($a,$b){return $a['sort']>$b['sort']?1:-1;});
 
 
 			$selector = '';
-			//sélecteurs spéciaux (eg : dictionnary doit prendre uniquement la derniere filter-value car peut être a depth ++)
+			//sélecteurs spéciaux (eg : dictionary doit prendre uniquement la derniere filter-value car peut être a depth ++)
 			if(isset($fieldType->filter['attributes']) && isset($fieldType->filter['attributes']['data-value-selector'])){
 				$selector = "data-value-selector=".$fieldType->filter['attributes']['data-value-selector'];
 			}
@@ -270,7 +270,7 @@ uasort ($footerMenu , function($a,$b){return $a['sort']>$b['sort']?1:-1;});
 			</div>
 			<input type="text" class="comment-keyword form-control">
 			<div class="input-group-append">
-				<div class="btn text-muted btn-light border" onclick="history_search()"><i class="fas fa-search"></i></div>
+				<div class="btn text-muted btn-light border" onclick="core_history_search()"><i class="fas fa-search"></i></div>
 			</div>
 	    </div>
 	    <div class="history-add mb-2" data-tooltip   title="Ajouter un commentaire ici..." onclick="history_add()"><i class="far fa-comment-dots"></i></div>
@@ -285,10 +285,10 @@ uasort ($footerMenu , function($a,$b){return $a['sort']>$b['sort']?1:-1;});
 	            </div>
 	            <div class="history-content w-100" ondblclick="history_edit($(this).closest('.comment'))">{{{comment}}}</div>
 	            <div class="history-importance">
-	            	<input type="checkbox" data-type="checkbox" data-tooltip title="Important" onclick="history_importance(this)"/>
+	            	<input type="checkbox" data-type="checkbox" data-tooltip title="Important" onclick="core_history_importance_save(this)"/>
 	         	</div>
 	            <ul class="history-options">
-	                <li data-tooltip title="Supprimer" class="pointer history-delete-btn" onclick="history_delete(this)"><i class="far fa-trash-alt"></i></li>
+	                <li data-tooltip title="Supprimer" class="pointer history-delete-btn" onclick="core_history_delete(this)"><i class="far fa-trash-alt"></i></li>
 	            </ul>
 	            <div class="history-add" data-tooltip title="Ajouter un commentaire ici..." onclick="history_add(this)">
 	            	<i class="far fa-comment-dots"></i>
@@ -297,8 +297,8 @@ uasort ($footerMenu , function($a,$b){return $a['sort']>$b['sort']?1:-1;});
 	    </ul>
 	</div>
 
-	<!-- Composant dictionnary table -->
-	<div class="hidden component-dictionnary-table" data-id="" data-type="dictionnary-table"  data-dictionnary="{{parent.id}}">
+	<!-- Composant dictionary table -->
+	<div class="hidden component-dictionary-table" data-id="" data-type="dictionary-table"  data-dictionary="{{parent.id}}">
 	    <table id="" class="table table-striped table-bordered">
 	        <thead class="bg-secondary text-light">
 	            <tr>
@@ -341,12 +341,12 @@ uasort ($footerMenu , function($a,$b){return $a['sort']>$b['sort']?1:-1;});
 					<div class="row">
 						<!-- search results -->
 						<div class="col-xl-12">
-							<table id="permissions" class="table table-striped" data-entity-search="core_right_search">
+							<table id="permissions" class="table table-striped" data-entity-search="core_permission_right_search">
 								<thead class="permission-firm-block">
 					                <tr>
 					                    <th class="col-target align-middle">Etablissement concerné</th>
 					                    <th colspan="6" class="col-read">
-					                    	<select id="permission-firm" class="form-control form-control-sm w-100" onchange="core_right_search()"></select>
+					                    	<select id="permission-firm" class="form-control form-control-sm w-100" onchange="core_permission_right_search()"></select>
 					                    </th>
 										
 					                  

+ 11 - 1
function.php

@@ -1934,6 +1934,16 @@ function date_workable_diff($start,$end,$openStartHour = 9,$openEndHour = 18,$lu
 		'days' => $deltaDays
 	);
 }
-
+if (!function_exists('getallheaders')) {
+    function getallheaders() {
+    $headers = [];
+    foreach ($_SERVER as $name => $value) {
+        if (substr($name, 0, 5) == 'HTTP_') {
+            $headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
+        }
+    }
+    return $headers;
+    }
+}
 
 ?>

+ 1 - 1
header.php

@@ -22,7 +22,7 @@ if(empty($cssModule) && ($page=='index.php' || $page==basename(ROOT_URL) || $pag
 
 if(isset($_['embedded'])) $cssModule[]='embedded';
 
-if(!isset($_['admin_login']) && file_exists('enabled.maintenance') && !$myUser->connected()){
+if(!isset($_['admin_login']) && file_exists(File::dir().SLASH.'enabled.maintenance') && !$myUser->connected()){
     isset($_['error']) && !empty($_['error']) ? header('location: maintenance.php?error='.$_['error']) : header('Location: maintenance.php');
     exit();
 } else {

+ 3 - 0
install.php

@@ -294,6 +294,9 @@ function install_core($parameters,$custom){
 	file_put_contents(__DIR__.DIRECTORY_SEPARATOR.'constant.php',$constantStream);
 
 	require_once(__DIR__.DIRECTORY_SEPARATOR.'constant.php');
+
+	if(!file_exists(File::core())) mkdir(File::core(),0755,true);
+
 	require_once(__ROOT__.'class'.SLASH.'Entity.class.php');
 
 

+ 40 - 35
js/component.js

@@ -125,7 +125,7 @@ function init_components(selector){
 
 					window.componentQueue['history'].timeout = setTimeout(function(){
 						$.action({
-							action : 'history_search',
+							action : 'core_history_search',
 							scopes : window.componentQueue['history'].scopes,
 							showImportant : true
 						},function(r){
@@ -158,7 +158,7 @@ function init_components(selector){
 					if(panel.hasClass('fold')) return;
 					if(input.attr('data-uid')) panel.attr('data-uid',input.attr('data-uid'));
 					if(data.scope) panel.attr('data-scope',data.scope);
-					history_search(function(){
+					core_history_search(function(){
 						//Redimensionnement du panel historique
 						setTimeout(function(){
 							uid = $('.history-panel').panelResize({direction : 'left'});
@@ -176,7 +176,7 @@ function init_components(selector){
 						if(target.hasClass('history-panel') || target.hasClass('comments') || !targetInPanel){
 							$('li.comment:not(.hidden)').each(function(){
 							    if($(this).find('.history-content .trumbowyg-editor-visible').length && $(this).find('.history-content .trumbowyg-editor').text().length)
-							        history_save(this);
+							        core_history_save(this);
 							});
 						}
 						if(targetInPanel) return;
@@ -386,7 +386,7 @@ function init_components(selector){
 				if(data.slug){
 					if(!data.depth) data.depth = 1;
 					$.action({
-						action: 'load_dictionnary_component',
+						action: 'core_dictionary_component_load',
 						slug: data.slug,
 						depth: data.depth,
 						multiLevelSelect: data.multiLevelSelect,
@@ -493,9 +493,9 @@ function init_components(selector){
 					var tags = id.split(',');
 
 
-					if(input.data('dictionnarySlug') && input.data("data-autocomplete-value") != 'label'){
+					if(input.data('dictionarySlug') && input.data("data-autocomplete-value") != 'label'){
 						$.action({
-							action : 'tag_list_by_id',
+							action : 'core_tag_list_by_id',
 							id : id
 						},function(response){
 							for(var key in response.tags){
@@ -527,17 +527,17 @@ function init_components(selector){
 					},500);
 				});
 
-				if(!input.data('autocomplete') && input.data('dictionnarySlug'))
-					input.data('autocomplete','tag_list_autocomplete');
+				if(!input.data('autocomplete') && input.data('dictionarySlug'))
+					input.data('autocomplete','core_tag_list_autocomplete');
 
 				if(input.data('autocomplete')){
-					var dictionnarySlug = input.data('dictionnarySlug');
+					var dictionarySlug = input.data('dictionarySlug');
 					$(picker).autocomplete({
 						action: input.data('autocomplete'),
 						selectEqual : false, //evite le select auto du tag test quand on veux taper test2
 						suggest : true,
 						dynamicData : function(){
-							return dictionnarySlug ? { parent : dictionnarySlug} : {}
+							return dictionarySlug ? { parent : dictionarySlug} : {}
 						},
 						onClick : function(selected,element){
 
@@ -654,7 +654,10 @@ function init_components(selector){
 
 			case 'firm':
 				//autocomplete classique
-				input.component_autocomplete('firm');
+				input.component_autocomplete('firm',{
+					edit : 'core_firm_by_uid',
+					autocomplete : 'core_firm_autocomplete'
+				});
 			break;
 
 			case 'map':
@@ -794,6 +797,8 @@ function init_components(selector){
 			case 'contact':
 				//autocomplete classique
 				input.component_autocomplete('contact',{
+					edit : 'core_contact_by_uid',
+					autocomplete : 'core_contact_autocomplete',
 					skin  :  function(item){
 						var html = '';
 						var re = new RegExp(input.val(),"gi");
@@ -913,7 +918,7 @@ function init_components(selector){
 					userPicker.addClass('hidden');
 					window.componentQueue.user.timeout = setTimeout(function(){
 						$.action({
-							action : 'user_by_uid',
+							action : 'core_user_by_uid',
 							uids : Object.keys(window.componentQueue.user.uids)
 						},function(r){
 							for(var key in window.componentQueue.user.components){
@@ -974,7 +979,7 @@ function init_components(selector){
 					types = input.data('types').split(',');
 				//aucompletion sur le nom des users / rangs
 				userPicker.autocomplete({
-					action : 'user_autocomplete',
+					action : 'core_user_autocomplete',
 					data : {
 						types : types,
 						scope : input.attr('data-scope')
@@ -1353,7 +1358,7 @@ function init_components(selector){
 					},
 					geocode: function(location){
 						$.action({
-							action: 'location_detail_search',
+							action: 'core_location_detail_search',
 							locationId: location.locationId
 						}, function(r){
 							if(input.attr('data-geocode-callback')!=null && input.attr('data-geocode-callback').length) {
@@ -1404,7 +1409,7 @@ function init_components(selector){
 			 * data-parent-id		: l'id de la liste parente associée
 			 * data-output		: id/slug définit la valueur de sortie de l'input (slug de la liste ou id de la liste (defaut))
 			 */
-			case 'dictionnary':
+			case 'dictionary':
 				var data = input.data();
 				var slug = input.attr('data-slug') ? input.attr('data-slug') : "";
 				var parentId = input.attr('data-parent-id') && input.attr('data-parent-id').length ? input.attr('data-parent-id') : "";
@@ -1413,7 +1418,7 @@ function init_components(selector){
 
 
 				$.action({
-					action : 'load_dictionnary_component',
+					action : 'core_dictionary_component_load',
 					slug: slug,
 					parentId : parentId,
 					depth : data.depth,
@@ -1421,7 +1426,7 @@ function init_components(selector){
 					value: input.attr('data-value')
 				},function(r){
 					var children = r.content && r.content.childs ? r.content.childs : r.content;
-					input.attr('onchange', 'get_sub_dictionnary(this, "'+input.attr('name')+'",'+1+');');
+					input.attr('onchange', 'get_sub_dictionary(this, "'+input.attr('name')+'",'+1+');');
 					input.html('');
 					input.append('<option value=""> - </option>');
 
@@ -1447,7 +1452,7 @@ function init_components(selector){
 			case 'dropzone':
 				console.warn('[DEPRECATED] : Dropzone doit être remplacé par le composant file');
 				if(input.find('form').length != 0 || input.find('ul>li').length) break;
-				if(!input.attr('data-action')) input.attr('data-action','action.php?action=upload_temporary_file');
+				if(!input.attr('data-action')) input.attr('data-action','action.php?action=core_temporary_file_upload');
 				var readonly = input.attr('data-readonly') == "true" ? true : false;
 				if(!input.get(0).hasAttribute('id')) input.attr('id',generate_uuid(10));
 				var customTpl = input.find('> *:not(:visible)');
@@ -2913,7 +2918,7 @@ function init_components(selector){
 					var plugin = $('.plugin.active',modal).attr('data-path');
 					if(!plugin) return;
 					$('.entity-list').fill({
-						action:'search_entities',
+						action:'core_entity_search',
 						plugin : plugin
 					},function(){
 						$('.entity-list .entity').click(function(){
@@ -2929,7 +2934,7 @@ function init_components(selector){
 					var value = input.val();
 					if(!value) return $('>span',component).html('');
 					$.action({
-						action : 'entity_edit',
+						action : 'core_entity_edit',
 						path : value
 					},function(response){
 						$('>span',component).html('<span class="text-muted">'+response.plugin.name+'</span> <i class="fas fa-chevron-right"></i> '+response.label);
@@ -2938,7 +2943,7 @@ function init_components(selector){
 
 				$(component).off('click').click(function(){
 					modal.modal('show');
-					$('.plugin-list',modal).fill({action:'search_plugin',includeCore : true},function(){
+					$('.plugin-list',modal).fill({action:'core_plugin_search',includeCore : true},function(){
 						$('.plugin',modal).click(function(){
 							$('.plugin',modal).removeClass('active');
 							$(this).addClass('active');
@@ -3056,7 +3061,7 @@ function init_components(selector){
 						var treeSearch = function(folderPath){
 
 							$.action({
-								action: 'file_search',
+								action: 'core_file_search',
 								keyword : '',
 								//sort : sort,
 								root :data.root,
@@ -3118,17 +3123,17 @@ function init_components(selector){
 
 			break;
 			/**
-			 * data-dictionnary : Le slug du dictionnary à utiliser
+			 * data-dictionary : Le slug du dictionary à utiliser
 			 */
-			case 'dictionnary-table':
-				if(input.hasClass('component-dictionnary-table')) return;
-				if(!input.attr('data-dictionnary') || !input.attr('data-dictionnary').length) return;
-				var tpl = $('.component-dictionnary-table').get(0).outerHTML;
+			case 'dictionary-table':
+				if(input.hasClass('component-dictionary-table')) return;
+				if(!input.attr('data-dictionary') || !input.attr('data-dictionary').length) return;
+				var tpl = $('.component-dictionary-table').get(0).outerHTML;
 				var inputData = input.data();
 
 				$.action({
-					action: 'load_dictionnary_component',
-					slug : input.attr('data-dictionnary')
+					action: 'core_dictionary_component_load',
+					slug : input.attr('data-dictionary')
 				},function(r){
 					if(!r.content) {
 						input.append('<div class="alert alert-warning mb-0"><i class="fas fa-exclamation-triangle mr-2"></i>Liste spécifiée inexistante</div>');
@@ -3138,16 +3143,16 @@ function init_components(selector){
 				 	input.append(list);
 				 	list.removeClass('hidden');
 
-				 	dictionnary_table_refresh(list);
+				 	dictionary_table_refresh(list);
 
 					//Save
 					input.on('click','thead .btn-success',function(){
 						var line = $(this).closest('tr');
 						var data = {
-							action:   inputData.saveAction ? inputData.saveAction : 'dictionnary_table_save',
+							action:   inputData.saveAction ? inputData.saveAction : 'core_dictionary_table_save',
 							label: line.find('input.list-label').val(),
 							id: list.attr('data-id'),
-							list: list.attr('data-dictionnary')
+							list: list.attr('data-dictionary')
 						};
 						if(list.find('input.list-slug')) data.slug = $('input.list-slug', list).val();
 
@@ -3155,7 +3160,7 @@ function init_components(selector){
 							list.attr('data-id', '');
 							line.find('input').val('');
 							$.message('success','Enregistré');
-							dictionnary_table_refresh(list);
+							dictionary_table_refresh(list);
 						});
 					});
 
@@ -3164,7 +3169,7 @@ function init_components(selector){
 						if(!confirm('Êtes-vous sûr de vouloir supprimer cet élément de liste ?')) return;
 						var line = $(this).closest('tr');
 						$.action({
-							action:  inputData.deleteAction ? inputData.deleteAction : 'delete_dictionnary',
+							action:  inputData.deleteAction ? inputData.deleteAction : 'core_dictionary_delete',
 							id: line.attr('data-id')
 						},function(r){
 							line.remove();
@@ -3177,7 +3182,7 @@ function init_components(selector){
 					input.on('click','tbody tr .btn-edit',function(){
 						var line = $(this).closest('tr');
 						$.action({
-							action:  inputData.editAction ? inputData.editAction : 'edit_dictionnary',
+							action:  inputData.editAction ? inputData.editAction : 'core_dictionary_edit',
 							id: line.attr('data-id')
 						},function(r){
 							list.find('input.list-label').val(r.label);

+ 38 - 35
js/filter.component.js

@@ -25,14 +25,14 @@
  nb 2: ce composant fonctionne avec les templates de type de filtres situés dans la page footer, exemple de type de filtre
  nb 3: les templates subcolumn référencent le plugin workflow (@TODO: à commenter par VC)
 
-<div class="filter-value-block" data-value-type="dictionnary" data-value-selector=".filter-value:last-child">
+<div class="filter-value-block" data-value-type="dictionary" data-value-selector=".filter-value:last-child">
 	<select class="form-control filter-operator border-0 text-primary">
 		<option value="=">Égal</option>
 		<option value="!=">Différent</option>
 		<option value="IS NULL"  data-values="0">Non Renseigné</option>
 		<option value="IS NOT NULL" data-values="0">Renseigné</option>
 	</select>
-	<select data-template="dictionnary" data-slug="{{slug}}" data-depth="{{depth}}" class="form-control filter-value" data-disable-label></select>
+	<select data-template="dictionary" data-slug="{{slug}}" data-depth="{{depth}}" class="form-control filter-value" data-disable-label></select>
 </div>
 
 data-value-type="" : permet de définir le data-type si la donnée est un composant
@@ -168,7 +168,7 @@ var FilterBox = function(input,options){
 			if(parent.find('.condition').length==0) parent.parent().remove();
 		}).on('click',' li .btn-delete',function(){
 			var line = $(this).closest('li.condition');
-			object.filter_remove(line);
+			object.core_filter_delete(line);
 		}).on('click','.btn-search',function(){
 			object.search();
 		}).on('keypress','.filter-keyword, .filter-value input',function(e){
@@ -178,17 +178,17 @@ var FilterBox = function(input,options){
 		}).on('click','.btn-search-save',function(e){
 			e.preventDefault();
 			e.stopPropagation();
-			object.filter_save_edit();
+			object.core_filter_save_edit();
 		//Enregistrement de la recherche courante
 		}).on('click','.btn-search-save-submit',function(e){
 			e.preventDefault();
 			e.stopPropagation();
-			object.filter_save();
+			object.core_filter_save();
 		//Définition d'une recherche pré enregistrée en global ou pas
 		}).on('click','.btn-search-global',function(e){
 			e.preventDefault();
 			e.stopPropagation();
-			object.filter_save_global($(this).closest('.btn-search-load'));
+			object.core_filter_global_save($(this).closest('.btn-search-load'));
 		//Suppression d'une recherche pré enregistrée
 		}).on('click','.btn-search-load > .btn-search-delete',function(e){
 			if(!confirm('Êtes-vous sûr de supprimer cette recherche définitivement ?')) return;
@@ -203,7 +203,7 @@ var FilterBox = function(input,options){
 			$('.filter-keyword',object.box).val('');
 			object.filter_clear_button();
 			$('.condition:not(.hidden)',object.box).each(function(i,element){
-				object.filter_remove($(element));
+				object.core_filter_delete($(element));
 			});
 			$('.condition',object.box).removeClass('error');
 		});
@@ -214,26 +214,28 @@ var FilterBox = function(input,options){
 			object.box.toggleClass('advanced');
 		});
 
-	 	//Preset des filtres depuis l'url si défini
-	 	var filters = $.urlParam('filters');
-	 	if(filters && filters!='' && (input.attr('data-urlsearch')==null || input.attr('data-urlsearch')=="true")){
-	 		filters = JSON.parse(atob_unicode(filters));
+		//Preset des filtres depuis l'url si défini
+		var filters = $.urlParam('filters');
+		if(filters && filters!='' && (input.attr('data-urlsearch')==null || input.attr('data-urlsearch')=="true")){
+			filters = JSON.parse(atob(filters));
 		} else if (input.attr('data-default') && input.attr('data-default').length){
 			//Preset des filtres depuis l'attribut data-default
-	 		filters = JSON.parse(input.attr('data-default'));
-
-	 		//Récupération du type de filtre pour la colonne ciblée
-	 		$.each(filters.a, function(i, filter){
-	 			if(filter.c==null || !filter.c.length || (filter.t!=null && filter.t.length)) return;
-
-	 			var option = $('option[value="'+filter.c+'"]', object.input);
-	 			if(!option.length){
-	 				delete filters.a[i];
-	 				return;
-	 			}
-	 			filters.a[i]['t'] = option.attr('data-filter-type');
-	 			filters.a[i]['o'] = filter.o.toLowerCase();
-	 		});
+			filters = JSON.parse(input.attr('data-default'));
+
+			//Récupération du type de filtre pour la colonne ciblée
+			$.each(filters.a, function(i, filter){
+				if(filter.c==null || !filter.c.length || (filter.t!=null && filter.t.length)) return;
+
+				var option = $('option[value="'+filter.c+'"]', object.input);
+				if(!option.length){
+					delete filters.a[i];
+					return;
+				}
+				filters.a[i]['t'] = option.attr('data-filter-type');
+				filters.a[i]['o'] = filter.o.toLowerCase();
+			});
+		} else {
+			filters = "";
 		}
 
 		if(filters){
@@ -286,7 +288,7 @@ FilterBox.prototype.filter_search_remove = function(uid){
 	var object = this;
 
 	$.action({
-		action: 'filter_remove',
+		action: 'core_filter_delete',
 		slug: object.slug,
 		uid: uid,
 		global: $('.btn-search-load[data-uid="'+uid+'"]',object.box).attr('data-global')
@@ -322,7 +324,7 @@ FilterBox.prototype.filter_clear_button = function(){
 };
 
 //Enregistrement d'une recherche (edition nom + options)
-FilterBox.prototype.filter_save_edit = function(){
+FilterBox.prototype.core_filter_save_edit = function(){
 	var object = this;
 	//var data = object.filters();
 	var button = $('.btn-search-save',object.box);
@@ -339,7 +341,7 @@ FilterBox.prototype.filter_save_edit = function(){
 };
 
 //Passage d'une recherche en global / privé
-FilterBox.prototype.filter_save_global = function(element){
+FilterBox.prototype.core_filter_global_save = function(element){
 	var object = this;
 	var uid = element.attr('data-uid');
 	var state = element.attr('data-global') == '1';
@@ -347,7 +349,7 @@ FilterBox.prototype.filter_save_global = function(element){
 	state = state ? 0:1 ;
 
 	$.action({
-		action: 'filter_save_global',
+		action: 'core_filter_global_save',
 		slug: object.slug,
 		uid: uid,
 		state: state,
@@ -358,7 +360,7 @@ FilterBox.prototype.filter_save_global = function(element){
 };
 
 //Enregistrement d'une recherche
-FilterBox.prototype.filter_save = function(){
+FilterBox.prototype.core_filter_save = function(){
 	var object = this;
 	var data = object.filters();
 	if(!data.keyword.length && !data.advanced.length) {
@@ -376,7 +378,7 @@ FilterBox.prototype.filter_save = function(){
 	input.val('');
 
 	$.action({
-		action : 'filter_save',
+		action : 'core_filter_save',
 		slug : object.slug,
 		label : label,
 		filters : data
@@ -480,6 +482,7 @@ FilterBox.prototype.filter_refresh = function(condition, refreshOperator, data){
 		if(dataAttributes.values) valueInput.attr('data-values',JSON.stringify(dataAttributes.values));
 
 		//Si on n'a qu'un champ à fill ET qu'on a plusieurs valeurs disponibles ET qu'on a un value-separator défini, on retravaille le champ des valeurs
+		//Besoin de faire ça car pour les filtres qui ont plusieurs valeurs dans 1 seul champ, on split leur valeurs lors de la recherche, il faut donc les join quand on les remet
 		if(repeat==1 && (data && data.value && data.value.length>1) && defaultView['value-separator']){
 			values = data.value.join(defaultView['value-separator']);
 			data.value = [];
@@ -566,7 +569,7 @@ FilterBox.prototype.filter_get_line = function(element){
 	}
 
 	if(line.column == null || line.column == ''){
-		object.filter_remove(element);
+		object.core_filter_delete(element);
 		return;
 	} else {
 		line.operator = element.find('> .filter-operator select').val();
@@ -710,7 +713,7 @@ FilterBox.prototype.filter_search_execute = function(uid,showFilters,callback){
 	var search = object.searches[uid];
 	$.urlParam('filters','');
 	$('.condition:not(.hidden)',object.box).each(function(i,element){
-		object.filter_remove($(element));
+		object.core_filter_delete($(element));
 	});
 	$('.condition',object.box).removeClass('error');
 	$('.filter-keyword',object.box).val(search.filters.keyword);
@@ -728,7 +731,7 @@ FilterBox.prototype.filter_search_load = function(callback){
 	var object = this;
 
 	$.action({
-		action : 'filter_load',
+		action : 'core_filter_search',
 		slug : object.slug,
 	},function(response){
 		var savedSearch = $('.saved-search-container');
@@ -791,7 +794,7 @@ FilterBox.prototype.filter_search_load = function(callback){
 };
 
 //Supression d'un filtre et de ses parents vides.
-FilterBox.prototype.filter_remove = function(line){
+FilterBox.prototype.core_filter_delete = function(line){
 	var object = this;
 	var group = line.closest('ul.group');
 

+ 131 - 118
js/main.js

@@ -202,7 +202,7 @@ function core_login(element){
 	var data = form.toJson(true);
 	data.redirect = form.attr('data-redirect');
 	data.url = form.attr('data-url');
-	data.action = 'login';
+	data.action = 'core_login';
 
 	isProcessing = true;
 	$.action(data
@@ -221,7 +221,7 @@ function core_login(element){
 
 function core_logout(url){
 	$.action({
-		action:'logout',
+		action:'core_logout',
 		url: url
 	},function(r){
 		localStorage.setItem('configuration',JSON.stringify({'inactivityDelay' : null}));
@@ -252,7 +252,7 @@ function init_setting(parameter){
 
 	switch(parameter.section){
 		case 'plugin':
-			search_plugin();
+			core_plugin_search();
 
 			$('.section-plugin').on('change', 'input.toggle', function(){
 				var input = $(this);
@@ -269,27 +269,29 @@ function init_setting(parameter){
 					  .prepend(label);
 
 				$.action({
-					action : 'change_plugin_state',
+					action : 'core_plugin_state_save',
 					plugin : input.closest('li').attr('data-id'),
 					state: value ? 1 : 0
 				}, function(r){
-
+					core_plugin_firm_show();
 				}, function(r){
 					button.text(value?'Activer':'Désactiver')
 						  .toggleClass('text-success text-muted')
 						  .prepend(label);
 					input.prop('checked',!value);
+					core_plugin_firm_show();
 				});
+				
 			});
 		break;
 		case 'user':
-			search_user();
+			core_user_search();
 		break;
 		case 'firmPlugin':
-			search_firm_plugin();
+			core_firm_plugin_search();
 		break;
 		case 'userfirmrank':
-			search_userfirmrank();
+			core_userfirmrank_search();
 		break;
 		case 'log':
 			$('#logs').sortable_table({
@@ -298,25 +300,25 @@ function init_setting(parameter){
 		break;
 
 		case 'rank':
-			search_rank();
+			core_rank_search();
 		break;
 
-		case 'dictionnary':
-			search_dictionnary();
+		case 'dictionary':
+			core_dictionary_search();
 			$('#label').blur(function(){
 				if($('#label').val() != '' && $('#slug').val() == ''){
 					$('#slug').off('click');
-					dictionnary_slug_proposal($('#label'), $('#parent'));
+					core_dictionary_slug_proposal($('#label'), $('#parent'));
 				}
 			});
 			$('#slug').off('click');
 			$('#slug').on('click', function(){
 				if($('#label').val() != '' && $('#slug').val() == '')
-					dictionnary_slug_proposal($('#label'), $('#parent'));
+					core_dictionary_slug_proposal($('#label'), $('#parent'));
 			});
 		break;
 		case 'right':
-			search_right();
+			core_right_search();
 		break;
 		default:
 			if(parameter.section!= null){
@@ -370,7 +372,7 @@ function search_log(exportMode, callback){
 
 	isProcessing = true;
 	$('#logs').fill({
-		action:'search_log',
+		action:'core_search_log',
 		filters: box.filters(),
 		sort: $('#logs').sortable_table('get'),
 		export: !exportMode ? false : exportMode,
@@ -384,17 +386,17 @@ function search_log(exportMode, callback){
 
 /** USER FIRM RANK**/
 // SEARCH
-function search_userfirmrank(callback){
+function core_userfirmrank_search(callback){
 	$('#userfirmranks').fill({
 		firm : $('#firm').val(),
-		action:'search_userfirmrank'
+		action:'core_userfirmrank_search'
 	},function(){
 		if(callback!=null) callback();
 	});
 }
 
 // SAVE
-function save_userfirmrank(element){
+function core_user_savefirmrank(element){
 	if(isProcessing) return;
 	var button = $(element);
 	var data = $.getForm('#userfirmrankForm');
@@ -418,17 +420,17 @@ function save_userfirmrank(element){
 		$('#firm').val($("#firm option:first").val());
 		$('#rank').val($("#rank option:first").val());
 		isProcessing = false;
-		search_userfirmrank();
+		core_userfirmrank_search();
 	});
 }
 
 // EDIT
-function edit_userfirmrank(element){
+function core_userfirmrank_edit(element){
 	var form = $('#userfirmrankForm');
 	var line = $(element).closest('tr');
 
 	$.action({
-		action:'edit_userfirmrank',
+		action:'core_userfirmrank_edit',
 		id:line.attr('data-id')
 	},function(r){
 		$.setForm(form,r);
@@ -439,14 +441,14 @@ function edit_userfirmrank(element){
 }
 
 // DELETE
-function delete_userfirmrank(element){
+function core_userfirmrank_delete(element){
 	if(isProcessing) return;
 	if(!confirm('Êtes vous sûr de vouloir supprimer ce lien Établissement / Utilisateur / Rang ?')) return;
 	var line = $(element).closest('tr');
 
 	isProcessing = true;
 	$.action({
-		action : 'delete_userfirmrank',
+		action : 'core_userfirmrank_delete',
 		id : line.attr('data-id')
 	},function(r){
 		isProcessing = false;
@@ -519,9 +521,9 @@ function core_firm_delete(element){
 
 /** FIRM PLUGINS **/
 // SEARCH
-function search_right(callback){
+function core_right_search(callback){
 	$('#rights').fill({
-		action: 'search_right',
+		action: 'core_right_search',
 		targetUid: $('#targetUid').attr('data-rank'),
 		firm: $('#firm').val()
 	},function(r){
@@ -531,10 +533,10 @@ function search_right(callback){
 }
 
 // TOGGLE RIGHT
-function toggle_right(element){
+function core_right_toggle(element){
 	var line = $(element).closest('tr');
 	$.action({
-		action:'toggle_right',
+		action:'core_right_toggle',
 		targetUid:$('#targetUid').attr('data-rank'),
 		targetScope: 'rank',
 		firm:$('#firm').val(),
@@ -545,9 +547,9 @@ function toggle_right(element){
 }
 
 // SEARCH
-function search_firm_plugin(callback){
+function core_firm_plugin_search(callback){
 	$('#firmplugins').fill({
-		action: 'search_firm_plugin',
+		action: 'core_firm_plugin_search',
 		firm: $('#firm').val()
 	},function(r){
 		update_checkboxes(r);
@@ -556,11 +558,12 @@ function search_firm_plugin(callback){
 }
 
 // ENABLE/DISABLE
-function toggle_firm_plugin(element){
-	var line = $(element).closest('tr');
+function core_firm_plugin_save(element){
+	var line = $(element).closest('.item');
+
 	$.action({
-		action:'toggle_firm_plugin',
-		firm :$('#firm').val(),
+		action:'core_firm_plugin_save',
+		firm :$(element).closest('.firm-item').attr('data-id'),
 		state : $(element).prop('checked')?1:0,
 		plugin: line.attr('data-id')
 	});
@@ -590,16 +593,16 @@ function firm_logo_delete(element){
 
 /** USER **/
 // SEARCH
-function search_user(callback){
+function core_user_search(callback){
 	$('#users').fill({
-		action: 'search_user'
+		action: 'core_user_search'
 	},function(){
 		if(callback!=null) callback();
 	});
 }
 
 // SAVE
-function save_user(){
+function core_user_save(){
 	var form = $('#userFormAdmin');
 	var data = $.getForm(form);
 	data.id = form.attr('data-id');
@@ -610,15 +613,15 @@ function save_user(){
 		$('input',form).val('');
 		form.attr('data-id','');
 		init_components(form);
-		search_user();
+		core_user_search();
 	});
 }
 
 // EDIT
-function edit_user(element){
+function core_user_edit(element){
     var line = $(element).closest('tr');
     $.action({
-        action: 'edit_user',
+        action: 'core_user_edit',
         login: line.attr('data-user')
     },function(r){
         $.setForm('#userFormAdmin',r);
@@ -632,11 +635,11 @@ function edit_user(element){
 
 
 // DELETE
-function delete_user(element){
+function core_user_delete(element){
 	if(!confirm('Êtes vous sûr de vouloir supprimer cet utilisateur ?')) return;
 	var line = $(element).closest('tr');
 	$.action({
-		action : 'delete_user',
+		action : 'core_user_delete',
 		login : line.attr('data-user')
 	},function(r){
 		$.message('info','Utilisateur supprimé');
@@ -649,14 +652,14 @@ function delete_user(element){
 
 
 /* ACCOUNT **/
-function account_lost_password(element){
+function core_account_lost_password(element){
 	if(isProcessing) return;
 	var btn = $(element);
 	btn.addClass('btn-preloader').attr('disabled', true);
 
 	isProcessing = true;
 	$.action({
-		action: 'account_lost_password',
+		action: 'core_account_lost_password',
 		mail : $('#mail').val()
 	}, function(r){
 		isProcessing = false;
@@ -668,11 +671,11 @@ function account_lost_password(element){
 	});
 }
 
-function account_save(element){
+function core_account_save(element){
 	var data = $('#user-form').toJson();
 	data.login =  $('#login').val();
 	data.avatar = $('#avatar')[0].files[0];
-	data.action =  'account_save';
+	data.action =  'core_account_save';
 
 	$.action(data, function(r){
 		$('.password-field input').val('');
@@ -681,9 +684,9 @@ function account_save(element){
 	});
 }
 
-function account_api_save(element){
+function core_account_api_save(element){
 	var data = $('#account-api-form').toJson();
-	data.action =  'account_api_save';
+	data.action =  'core_account_api_save';
 
 	$.action(data, function(r){
 		$.message('success','Enregistré');
@@ -691,12 +694,12 @@ function account_api_save(element){
 }
 
 // SUPPRIME AVATAR USER
-function account_avatar_delete(element){
+function core_account_avatar_delete(element){
 	if(!confirm('Êtes vous sûr de vouloir supprimer l\'image ?')) return;
 	var imageComposer = $(element).parent().find("input[data-type='image']");
 
 	$.action({
-		action: 'account_avatar_delete',
+		action: 'core_account_avatar_delete',
 		login: $('#login').val()
 	}, function(r){
 		imageComposer.wrap('<form>').closest('form').get(0).reset();
@@ -708,41 +711,41 @@ function account_avatar_delete(element){
 
 /** RANKS **/
 // SEARCH
-function search_rank(callback){
+function core_rank_search(callback){
 	$('#ranks').fill({
-		action: 'search_rank'
+		action: 'core_rank_search'
 	},function(){
 		if(callback!=null) callback();
 	});
 }
 
 // SAVE
-function save_rank(){
+function core_rank_save(){
 	var data = $.getForm('#rankForm');
 	data.id = $('#rankForm').attr('data-id');
 	$.action(data,function(r){
 		$.message('success','Rang enregistré');
 		$('#rankForm input').val('');
 		$('#rankForm').attr('data-id','');
-		search_rank();
+		core_rank_search();
 	});
 }
 
 // EDIT
-function edit_rank(element){
+function core_rank_edit(element){
 	var line = $(element).closest('tr');
-	$.action({action:'edit_rank',id:line.attr('data-id')},function(r){
+	$.action({action:'core_rank_edit',id:line.attr('data-id')},function(r){
 		$.setForm('#rankForm',r);
 		$('#rankForm').attr('data-id',r.id);
 	});
 }
 
 // DELETE
-function delete_rank(element){
+function core_rank_delete(element){
 	if(!confirm('Êtes vous sûr de vouloir supprimer ce rang ?')) return;
 	var line = $(element).closest('tr');
 	$.action({
-		action : 'delete_rank',
+		action : 'core_rank_delete',
 		id : line.attr('data-id')
 	},function(r){
 		$.message('info','Rang supprimé');
@@ -753,14 +756,14 @@ function delete_rank(element){
 
 /** DICTIONNARY **/
 // SEARCH
-function search_dictionnary(callback){
+function core_dictionary_search(callback){
 	var parentValue = $('#parent').val();
 	parentValue != "" ? $('#prev-button').removeClass('hidden') :  $('#prev-button').addClass('hidden');
 	$('#dictionnaries').fill({
-		action:'search_dictionnary',
+		action:'core_dictionary_search',
 		parent : parentValue
 	},function(r){
-		reset_inputs($('#dictionnaryForm'), false, true);
+		reset_inputs($('#dictionaryForm'), false, true);
 		if(callback!=null) callback();
 		var tpl = $('#parent').find('option[value="{{id}}"]');
 		if(!tpl.parent('span').length) tpl.wrap('<span>').addClass('hidden');
@@ -768,36 +771,36 @@ function search_dictionnary(callback){
 }
 
 // SAVE
-function save_dictionnary(){
-	var data = $.getForm('#dictionnaryForm');
-	data.id = $('#dictionnaryForm').attr('data-id');
+function core_dictionary_save(){
+	var data = $.getForm('#dictionaryForm');
+	data.id = $('#dictionaryForm').attr('data-id');
 	data.parent = $('#parent').val();
 	$.action(data,function(r){
 		$.message('success','Liste enregistrée');
-		$('#dictionnaryForm input').val('');
-		$('#dictionnaryForm').attr('data-id','');
-		search_dictionnary();
+		$('#dictionaryForm input').val('');
+		$('#dictionaryForm').attr('data-id','');
+		core_dictionary_search();
 	});
 }
 
 // EDIT
-function edit_dictionnary(element){
+function core_dictionary_edit(element){
 	var line = $(element).closest('tr');
 	$.action({
-		action: 'edit_dictionnary',
+		action: 'core_dictionary_edit',
 		id: line.attr('data-id')
 	},function(r){
-		$.setForm('#dictionnaryForm',r);
-		$('#dictionnaryForm').attr('data-id',r.id);
+		$.setForm('#dictionaryForm',r);
+		$('#dictionaryForm').attr('data-id',r.id);
 	});
 }
 
 // DELETE
-function delete_dictionnary(element){
+function core_dictionary_delete(element){
 	if(!confirm('Êtes-vous sûr de vouloir supprimer cette liste ?')) return;
 	var line = $(element).closest('tr');
 	$.action({
-		action: 'delete_dictionnary',
+		action: 'core_dictionary_delete',
 		id: line.attr('data-id')
 	},function(r){
 		line.remove();
@@ -806,13 +809,13 @@ function delete_dictionnary(element){
 }
 
 // Remplissage de la liste (select) --> Dans les settings
-function get_dictionnary_items(elem, elemToFill){
+function get_dictionary_items(elem, elemToFill){
 	var parent = $(elem).closest('tr');
 	var id = $(parent).attr('data-id');
 	var	parentId = $(parent).attr('data-parent');
 
 	$(elemToFill).fill({
-		action:'search_dictionnary',
+		action:'core_dictionary_search',
 		parent : parentId.toString()
 	},function(){
 		$(elemToFill).val(id).change();
@@ -820,8 +823,8 @@ function get_dictionnary_items(elem, elemToFill){
 }
 
 // Ajout de sous-liste --> Dans les settings
-function add_sub_dictionnary(elem){
-	reset_inputs($('#dictionnaryForm'), false, true);
+function add_sub_dictionary(elem){
+	reset_inputs($('#dictionaryForm'), false, true);
 
 	var parent = $(elem).closest('tr');
 	var id = $(parent).attr('data-id');
@@ -830,19 +833,19 @@ function add_sub_dictionnary(elem){
 	if ($("#parent option[value='"+id+"']").length > 0)
 		$('#parent').val(id).change();
 	else {
-		get_dictionnary_items(elem, "#parent");
+		get_dictionary_items(elem, "#parent");
 		$('code').addClass('hidden');
 	}
 	$('#prev-button').removeClass('hidden');
 }
 
 // Récupération éléments de la liste précédente --> Dans les settings
-function previous_list_dictionnary(elem){
+function previous_list_dictionary(elem){
 	var selected = $('#parent > option:selected').val();
-	reset_inputs($('#dictionnaryForm'), false, true);
+	reset_inputs($('#dictionaryForm'), false, true);
 
 	$.action({
-		action: 'get_parent_dictionnary',
+		action: 'core_dictionary_get_parent',
 		selected: selected
 	}, function(r){
 		var data = r.rows[0];
@@ -860,12 +863,12 @@ function previous_list_dictionnary(elem){
 			else
 				$('#parent').append("<option value='"+value.id+"'>"+value.label+"</option>");
 		});
-		search_dictionnary();
+		core_dictionary_search();
 	});
 }
 
-// Récupération des sous-listes pour les champ de type "dictionnary" --> Où le module est appelé
-function get_sub_dictionnary(elem, name, currentDepth){
+// Récupération des sous-listes pour les champ de type "dictionary" --> Où le module est appelé
+function get_sub_dictionary(elem, name, currentDepth){
 	var input = $(elem);
 	var data = input.data();
 	data.output = data.output ? data.output : 'id';
@@ -875,7 +878,7 @@ function get_sub_dictionnary(elem, name, currentDepth){
 	var fieldName = name == '' ? input.attr('name') : name;
 
 	currentDepth -= currentDepth != 1 ? input.nextAll('select').length : 0;
-	if(input.closest('span.dictionnary-container').length != 0){
+	if(input.closest('span.dictionary-container').length != 0){
 		var id = input.nextAll().last().attr('id');
 		input.attr('id', id).nextAll().remove();
 	}
@@ -885,16 +888,16 @@ function get_sub_dictionnary(elem, name, currentDepth){
 		currentDepth += 1;
 
 		$.action({
-			action: 'search_dictionnary',
+			action: 'core_dictionary_search',
 			parent: selectValue
 		}, function(r){
 			var option = '';
-			if(input.closest('span.dictionnary-container').length == 0) input.wrap('<span class="dictionnary-container"></span>');
-			var newSelect = clone_input_dictionnary(input, selectValue, fieldName);
-			var currentDepth = input.closest('span.dictionnary-container').children('select').length;
+			if(input.closest('span.dictionary-container').length == 0) input.wrap('<span class="dictionary-container"></span>');
+			var newSelect = clone_input_dictionary(input, selectValue, fieldName);
+			var currentDepth = input.closest('span.dictionary-container').children('select').length;
 
 			if (input.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null") input.after('<label class="label-select">'+optSubLabel+'</label>');
-			newSelect.attr('onchange', 'get_sub_dictionnary(this, "'+fieldName+'", '+currentDepth+');');
+			newSelect.attr('onchange', 'get_sub_dictionary(this, "'+fieldName+'", '+currentDepth+');');
 			newSelect.append('<option value=""> - </option>');
 
 			$.each(r.rows, function(index, value){
@@ -912,14 +915,14 @@ function get_selected_values(elem, select){
 	var input = $(elem);
 	var data = input.data();
 	data.output = data.output ? data.output : 'id';
-	if(input.closest('span.dictionnary-container').length == 0) input.wrap('<span class="dictionnary-container"></span>');
+	if(input.closest('span.dictionary-container').length == 0) input.wrap('<span class="dictionary-container"></span>');
 	var fieldName = input.attr('name');
-	var currentDepth = 1+input.closest('span.dictionnary-container').children('select').length;
+	var currentDepth = 1+input.closest('span.dictionary-container').children('select').length;
 	var optSubLabel = select.sublistlabel;
 	var option = '';
 
 	if ( select.childs  &&  select.childs.length > 0) {
-		var newSelect = clone_input_dictionnary(input, select.id, fieldName);
+		var newSelect = clone_input_dictionary(input, select.id, fieldName);
 
 		if (newSelect.attr('data-disable-label') != "" && optSubLabel != "" && optSubLabel != "null" && optSubLabel != undefined) input.after('<label class="label-select">'+optSubLabel+'</label>');
 		newSelect.append('<option value=""> - </option>');
@@ -933,14 +936,14 @@ function get_selected_values(elem, select){
 			selected = "selected";
 		}
 
-		newSelect.attr('onchange', 'get_sub_dictionnary(this,"'+fieldName+'", '+currentDepth+');');
+		newSelect.attr('onchange', 'get_sub_dictionary(this,"'+fieldName+'", '+currentDepth+');');
 		option += '<option value="'+value[data.output]+'" data-parent="'+value.parent+'" data-sublabel="'+value.sublistlabel+'" '+selected+'>'+value.label+'</option>';
 	});
 	if(newSelect) newSelect.append(option);
 }
 
-// Clone du select de type "dictionnary"
-function clone_input_dictionnary(input, id, name){
+// Clone du select de type "dictionary"
+function clone_input_dictionary(input, id, name){
 	var newSelect = input.clone();
 	input.removeAttr('id').after(newSelect).after(' ');
 	newSelect.removeAttr("data-type").removeAttr('name').removeAttr('data-value');
@@ -950,12 +953,12 @@ function clone_input_dictionnary(input, id, name){
 }
 
 //Rafraîchit la table de la liste donnée
-//En lien avec le composant dictionnary_table
-function dictionnary_table_refresh(elem){
-	var id = $(elem).attr('data-dictionnary');
+//En lien avec le composant dictionary_table
+function dictionary_table_refresh(elem){
+	var id = $(elem).attr('data-dictionary');
 	var table = $(elem).find('table:eq(0)');
 	$.action({
-		action: 'dictionnary_table_search',
+		action: 'core_dictionary_table_search',
 		id: id
 	},function(r){
 		table.find('tbody tr:visible').remove();
@@ -969,10 +972,10 @@ function dictionnary_table_refresh(elem){
 	});
 }
 
-function dictionnary_slug_proposal(element, parent){
+function core_dictionary_slug_proposal(element, parent){
 	var line = $(element).closest('tr');
 	$.action({
-		action : 'dictionnary_slug_proposal',
+		action : 'core_dictionary_slug_proposal',
 		id : line.attr('data-id'),
 		label : $(element).val(),
 		parent : $(parent).val()
@@ -983,17 +986,27 @@ function dictionnary_slug_proposal(element, parent){
 
 /** PLUGINS **/
 // SEARCH
-function search_plugin(callback){
+function core_plugin_search(callback){
 	var list = $('#plugins');
 
 	list.fill({
-		action:'search_plugin'
+		action:'core_plugin_search'
 	},function(){
 		init_tooltips(list);
+		core_plugin_firm_show();
+		$('.firm-toggle').each(function(i,element){
+			$(element).prop('checked',$(element).attr('data-value')=='1');
+		});
 		if(callback!=null) callback();
 	});
 }
 
+function core_plugin_firm_show(){
+	$('#plugins .item').each(function(i,element){
+		$('.plugin-firm-block',element).toggleClass('hidden',!$('input.toggle',element).prop('checked'));
+	});
+}
+
 // RÉCUPÉRATION PARAMÈTRE URL
 var get_url_parameter = function get_url_parameter(sParam, string) {
 	var sPageURL = !string ? decodeURIComponent(window.location.search.substring(1)) : string;
@@ -1031,7 +1044,7 @@ function dropzone_delete_file(element){
 
 /* GENERAL SETTINGS */
 //Sauvegarde de la configuration générale
-function general_settings_save(){
+function core_general_settings_save(){
 	var data = $('#general-settings').toJson();
 	data.password_format = $('#password-format-form').attr('data-format');
 	
@@ -1039,10 +1052,10 @@ function general_settings_save(){
 		$.message('success', 'Configuration enregistrée');
 	});
 }
-function general_reset_password_delay(){
+function core_general_password_reset_delay(){
     if(!confirm('Êtes-vous sûr de vouloir forcer tous les utilisateurs à réinitialiser leurs mot de passe ?')) return;
     $.action({
-        action: 'general_reset_password_delay'
+        action: 'core_general_password_reset_delay'
     }, function(r){
         $.message('success', 'Validé');
     });
@@ -1062,7 +1075,7 @@ function toggle_maintenance(){
 		checkbox.is(':checked') ? checkbox.removeAttr('checked').prop('checked', false) : checkbox.attr('checked', true).prop('checked', true);
 		return;
 	}
-	general_settings_save();
+	core_general_settings_save();
 }
 
 
@@ -1688,12 +1701,12 @@ function core_right_delete(element){
 }
 
 // History
-function history_search(callback){
+function core_history_search(callback){
 	var panel = $('.history-panel');
 
 	$('.comments-loader', panel).removeClass('hidden');
 	$('.comments', panel).fill({
-		action: 'history_search',
+		action: 'core_history_search',
 		keyword: $('.comment-keyword').val(),
 		uid: panel.attr('data-uid'),
 		scope: panel.attr('data-scope'),
@@ -1743,7 +1756,7 @@ function history_edit(element){
 	$('.trumbowyg-editor',commentElement).focus();
 }
 
-function history_save(element){
+function core_history_save(element){
 	var comment = $(element);
 	var commentElement = $('.history-content', comment);
 
@@ -1763,7 +1776,7 @@ function history_save(element){
 	var importance = importanceElement.prop('checked') ? 'important' : 'normal';
 
 	$.action({
-		action: 'history_save',
+		action: 'core_history_save',
 		id: comment.attr('data-id'),
 		sort: comment.attr('data-sort'),
 		replaceSort:replaceSort,
@@ -1788,35 +1801,35 @@ function history_save(element){
 	});
 }
 
-function history_importance(element){
+function core_history_importance_save(element){
 	var importance = $(element).prop('checked') ? 'important' : 'normal';
 	var comment = $(element).closest('.comment');
 	var id = $(element).closest('.history-panel').attr('data-uid');
 	$.action({
-		action: 'history_importance',
+		action: 'core_history_importance_save',
 		id: comment.attr('data-id'),
 		importance : importance
 	},function(r){
 		comment.attr('data-importance', importance);
-		history_importance_count(id);
+		core_history_importance_save_count(id);
 
 	});
 }
 
-function history_delete(element){	
+function core_history_delete(element){	
 	if(!confirm('Êtes-vous sûr de vouloir supprimer ce commentaire ?')) return;
 	var comment = $(element).closest('.comment');
 	var id = $(element).closest('.history-panel').attr('data-uid');
 	$.action({
-		action: 'history_delete',
+		action: 'core_history_delete',
 		id: comment.attr('data-id')
 	},function(r){
 		comment.remove();
-		history_importance_count(id);
+		core_history_importance_save_count(id);
 	});
 }
 
-function history_importance_count(uid){
+function core_history_importance_save_count(uid){
 	var count = $('.history-importance input:checked').length;
 	var historyNotification = $('a[data-uid="'+uid+'"] .history-notification');
 	if(count == 0){

+ 3 - 3
js/plugins.js

@@ -842,7 +842,7 @@ $.fn.extend({
 							if(callback) callback();
 						}else{
 							$.action({
-								action : 'fill_colum_save',
+								action : 'core_table_colum_save',
 								slug : table.attr('data-slug'),
 								added : columns.added
 							},function(){
@@ -923,7 +923,7 @@ $.fn.extend({
 						addDynamicColumns(added);
 					}else{
 						$.action({
-							action : 'fill_column_load',
+							action : 'core_table_colum_search',
 							async : false,
 						},function(preferences){
 							plusButton.addClass('btn-preloader');
@@ -1313,7 +1313,7 @@ $.fn.extend({
 			});
 
 			obj.autocomplete({
-				action: 'location_search',
+				action: 'core_location_search',
 				delay : 300,
 				force: (o.force ? o.force : false),
 				items: (o.items ? o.items : 8),

+ 2 - 2
js/vendor/trumbowyg.plugins.js

@@ -1,6 +1,6 @@
 
 /* ===========================================================
- * trumbowyg.pasteImageSys1.js v1.0 basé sur trumbowyg.pasteImage.js v1.0
+ * trumbowyg.pasteImageKiss.js v1.0 basé sur trumbowyg.pasteImage.js v1.0
  * Basic base64 paste plugin for Trumbowyg
  * http://alex-d.github.com/Trumbowyg
  * ===========================================================
@@ -13,7 +13,7 @@
 
     $.extend(true, $.trumbowyg, {
         plugins: {
-            pasteImageSys1: {
+            pasteImageKiss: {
                 init: function (trumbowyg) {
                     trumbowyg.pasteHandlers.push(function (pasteEvent) {
                         try {

+ 2 - 2
maintenance.php

@@ -2,7 +2,7 @@
 require_once(__DIR__.DIRECTORY_SEPARATOR.'common.php');
 $mediaRoot = define_media_root();
 global $conf;
-if(file_exists('disabled.maintenance')){
+if(file_exists(File::dir().SLASH.'disabled.maintenance')){
 	header('Location: index.php');
 	exit();
 }
@@ -33,7 +33,7 @@ if(file_exists('disabled.maintenance')){
 		<div class="container-fluid">
 			<div class="row w-100 justify-content-md-center">
 				<div class="content-block col-md-6 col-sm-12">
-					<?php echo html_entity_decode(file_get_contents('enabled.maintenance')); ?>
+					<?php echo html_entity_decode(file_get_contents(File::dir().SLASH.'enabled.maintenance')); ?>
 				</div>
 			</div>
 			<p>Merci de revenir dans quelques instants</p>

+ 9 - 0
migration/migration.php

@@ -383,6 +383,12 @@ addStep('Employee : Ajout colonne state.', function($mode){
 	Employee::staticQuery('UPDATE {{table}} SET state = "'.Employee::ACTIVE.'";');
 });
 
+addStep('Dictionary : Correctif de la faute historique', function($mode){
+	Dictionary::staticQuery('RENAME TABLE `dictionnary` TO {{table}};');
+});
+
+
+
 
 addStep('Host : input client en dynamicForm', function($mode){
 	Plugin::need('dynamicform/DynamicForm, dynamicform/DynamicField, dynamicform/DynamicValue, host/Machine, client/Client');
@@ -432,6 +438,9 @@ addStep('Host : input client en dynamicForm', function($mode){
 	}
 });
 
+addStep('Plugin : Migration enabled.json vers /file/core/plugin.json', function($mode){
+	rename(__ROOT__.PLUGIN_PATH.'enabled.json',File::core().SLASH.'plugin.json');
+});
 /** FIN DU SCRIPT **/
 
 

+ 2 - 3
plugin/activedirectory/AdServer.class.php

@@ -399,9 +399,8 @@ class AdServer extends Entity{
 		$newPassword = "\"" . $newPassword . "\"";
 		$len = strlen( $newPassword );
 		$newPassw = "";
-		for ( $i = 0; $i < $len; $i++ ){
-			$newPassw .= "{$newPassword{$i}}\000";
-		}
+		for ( $i = 0; $i < $len; $i++ )
+			$newPassw .= $newPassword[$i]."\000";
 		return array("unicodePwd" => $newPassw);
 	}
 

+ 1 - 1
plugin/client/Client.class.php

@@ -34,7 +34,7 @@ class Client extends Entity{
 		'state' => array('type'=>'list', 'label' => 'Etat'),
 		'pseudonym' => array('type'=>'text', 'label' => 'Pseudonyme'),
 		'code' => array('type'=>'text', 'label' => 'Code client'),
-		'category' => array('type'=>'dictionnary', 'label' => 'Catégorie','link'=>'class/Dictionnary.class.php'),
+		'category' => array('type'=>'dictionary', 'label' => 'Catégorie','link'=>'class/Dictionary.class.php'),
 		'siret' => array('type'=>'text', 'label' => 'N° SIRET'),
 		'comment' => array('type'=>'textarea', 'label' => 'Commentaire'),
 		'slug' => array('type'=>'text', 'label' => 'Slug'),

+ 18 - 18
plugin/client/action.php

@@ -14,10 +14,10 @@ Action::register('client_client_search',function(&$response){
 			
 			
 			// OPTIONS DE RECHERCHE, A ACTIVER POUR UNE RECHERCHE AVANCEE
-			$query = 'SELECT DISTINCT main.*,phone.value as phone,mail.value as mail,parent.id parentId,parent.label parentLabel,address.street,address.complement,address.zip,address.city,'.Firm::joinString('fi').','.Dictionnary::joinString('category').' FROM {{table}} main
+			$query = 'SELECT DISTINCT main.*,phone.value as phone,mail.value as mail,parent.id parentId,parent.label parentLabel,address.street,address.complement,address.zip,address.city,'.Firm::joinString('fi').','.Dictionary::joinString('category').' FROM {{table}} main
 			LEFT JOIN '.Client::tableName().' parent ON main.parent=parent.id 
 			LEFT JOIN '.Firm::tableName().' fi ON main.firm=fi.id 
-			LEFT JOIN '.Dictionnary::tableName().' category ON main.category=category.id 
+			LEFT JOIN '.Dictionary::tableName().' category ON main.category=category.id 
 			LEFT JOIN '.Contact::tableName().' phone ON phone.uid=main.id AND phone.scope="client" AND phone.type="mobile" 
 			LEFT JOIN '.Contact::tableName().' mail ON mail.uid=main.id AND mail.scope="client" AND mail.type="professional_mail" 
 			LEFT JOIN '.Address::tableName().' address ON address.uid=main.id AND address.scope="client" AND address.type="'.Address::MAIN.'" 
@@ -710,7 +710,7 @@ Action::register('client_contact_search',function(&$response){
 					case 'client':
 						require_once(__DIR__.SLASH.'Client.class.php');
 						$client = Client::getById($clientcontact->account);
-						if(!$client) continue;
+						if(!$client) continue 2;
 						$row['avatar'] = $client->logo();
 						$row['fullName'] = $client->label();
 						$row['link'] = 'index.php?module=client&page=sheet.client&id='.$row['account'];
@@ -1028,7 +1028,7 @@ Action::register('client_address_delete',function(&$response){
 	
 	/** HISTORY **/
 	//Récuperation d'une liste de history
-Action::register('client_history_search',function(&$response){
+Action::register('client_core_history_search',function(&$response){
 			global $myUser,$_;
 			if(!$myUser->can('client_history','read')) throw new Exception("Permission non accordée sur cette fiche");
 			if(!$myUser->can('client','read') && $_['id']!=0 && !$myUser->can('client_sheet','read',$_['id'])) throw new Exception("Permission non accordée sur cette fiche");
@@ -1098,7 +1098,7 @@ Action::register('client_history_search',function(&$response){
 		});
 	
 
-	Action::register('client_history_save',function(&$response){
+	Action::register('client_core_history_save',function(&$response){
 		global $myUser,$_,$myFirm;
 		User::check_access('client_history','edit');
 		
@@ -1130,7 +1130,7 @@ Action::register('client_history_search',function(&$response){
 	});
 
 
-	Action::register('client_history_delete',function(&$response){
+	Action::register('client_core_history_delete',function(&$response){
 		global $myUser,$_,$myFirm;
 		User::check_access('client_history','delete');
 		require_once(__DIR__.SLASH.'Client.class.php');
@@ -1228,8 +1228,8 @@ Action::register('client_history_search',function(&$response){
 
 			//convertion des catégories label -> bdd
 			$categoriesLabel = array();
-			$categoriesDictionnary = Dictionnary::bySlug('client_category');
-			foreach (Dictionnary::slugToArray('client_category',true) as $categoryKey=>$category) 
+			$categoriesDictionary = Dictionary::bySlug('client_category');
+			foreach (Dictionary::slugToArray('client_category',true) as $categoryKey=>$category) 
 				$categoriesLabel[$category->label] = $categoryKey;
 
 			//Convertion des adresses
@@ -1355,15 +1355,15 @@ Action::register('client_history_search',function(&$response){
 
 
 
-			$transformMapping['category'] = function($value,$client) use ($categoriesLabel,$categoriesDictionnary){
+			$transformMapping['category'] = function($value,$client) use ($categoriesLabel,$categoriesDictionary){
 				if(!isset($categoriesLabel[$value])){
-					$dictionnary = new Dictionnary();
-					$dictionnary->label = $value;
-					$dictionnary->state = Dictionnary::ACTIVE;
-					$dictionnary->slug = $categoriesDictionnary->slug.'_'.slugify($value);
-					$dictionnary->parent = $categoriesDictionnary->id;
-					$dictionnary->save();
-					$categoriesLabel[$value] = $dictionnary->id;
+					$dictionary = new Dictionary();
+					$dictionary->label = $value;
+					$dictionary->state = Dictionary::ACTIVE;
+					$dictionary->slug = $categoriesDictionary->slug.'_'.slugify($value);
+					$dictionary->parent = $categoriesDictionary->id;
+					$dictionary->save();
+					$categoriesLabel[$value] = $dictionary->id;
 				}
 				return $categoriesLabel[$value];
 			};
@@ -1401,8 +1401,8 @@ Action::register('client_history_search',function(&$response){
 									$options = array();
 									
 									
-									if($isDynamic[$key]['type']->slug =='dictionnary'){
-										$parent = Dictionnary::bySlug($isDynamic[$key]['meta']->slug);
+									if($isDynamic[$key]['type']->slug =='dictionary'){
+										$parent = Dictionary::bySlug($isDynamic[$key]['meta']->slug);
 										$options['slug'] = $parent->id;
 									}
 									

+ 12 - 12
plugin/client/client.plugin.php

@@ -43,18 +43,18 @@ function client_install($id){
     $conf->put('client_label_singular','client');
     $conf->put('client_holding_singular','holding');
 
-    $dictionnary = new Dictionnary();
-    $dictionnary->slug = 'client_category';
-    $dictionnary->label = 'Categorie de client';
-    $dictionnary->parent = 0;
-    $dictionnary->state = Dictionnary::ACTIVE;
-    $dictionnary->save();
-
-    $item = new Dictionnary();
+    $dictionary = new Dictionary();
+    $dictionary->slug = 'client_category';
+    $dictionary->label = 'Categorie de client';
+    $dictionary->parent = 0;
+    $dictionary->state = Dictionary::ACTIVE;
+    $dictionary->save();
+
+    $item = new Dictionary();
     $item->slug = 'client_category_none';
     $item->label = 'Aucune';
-    $item->parent = $dictionnary->id;
-    $item->state = Dictionnary::ACTIVE;
+    $item->parent = $dictionary->id;
+    $item->state = Dictionary::ACTIVE;
     $item->save();
 
     global $myFirm;
@@ -232,7 +232,7 @@ if( $myFirm->has_plugin('fr.core.export')){
 
 
 		$data['client']['value']['category']['value'] = 
-		isset($data['client']['value']['category']) && $data['client']['value']['category']['value']!=0 ? Dictionnary::getById($data['client']['value']['category']['value'])->label: 'Aucune';
+		isset($data['client']['value']['category']) && $data['client']['value']['category']['value']!=0 ? Dictionary::getById($data['client']['value']['category']['value'])->label: 'Aucune';
 		
 		if(!empty($data['client']['value']['type']['value'])) 
 			$data['client']['value']['type']['value'] = Client::types($data['client']['value']['type']['value'])['label'];
@@ -546,7 +546,7 @@ $sheet = array();
 		'sort' => 40,
 		'label' => 'Catégorie',
 		'block-class' => 'field-block',
-		'type' => 'dictionnary',
+		'type' => 'dictionary',
 		'attributes' => array(
 			'data-slug' => '"client_category"',
 			'data-value' => '"'.$client->category.'"'

+ 7 - 7
plugin/client/js/main.js

@@ -659,13 +659,13 @@ function client_address_copy(element){
 
 /** HISTORY **/
 //Récuperation d'une liste de history dans le tableau #historys
-function client_history_search(callback,exportMode){
+function client_core_history_search(callback,exportMode){
 	if($('.client-container').attr('data-id')=='') return;
 	
 	var box = new FilterBox('#client-history-filters');
 	
 	$('#historys').fill({
-		action:'client_history_search',
+		action:'client_core_history_search',
 		filters: box.filters(),
 		id: $('.client-container').attr('data-id'),
 		export:  !exportMode ? false : exportMode
@@ -678,8 +678,8 @@ function client_history_search(callback,exportMode){
 
 
 
-function client_history_save(callback){
-	var data = {action:'client_history_save',client:$.urlParam('id'),comment:$('#history-comment').val()}
+function client_core_history_save(callback){
+	var data = {action:'client_core_history_save',client:$.urlParam('id'),comment:$('#history-comment').val()}
 
 	if($('#history-comment').attr('data-id')) data.id = $('#history-comment').attr('data-id');
 
@@ -688,7 +688,7 @@ function client_history_save(callback){
 		$('#history-comment').val('');
 		
 		$('#history-comment').data('trumbowyg').empty()
-		client_history_search();
+		client_core_history_search();
 		if(callback) callback();
 	});
 }
@@ -707,12 +707,12 @@ function client_history_edit(element){
 
 }
 
-function client_history_delete(element){
+function client_core_history_delete(element){
 	if(!confirm('Êtes-vous sûr de vouloir supprimer cet historique client ?')) return;
 	var line = $(element).closest('.item-line');
 	
 	$.action({
-		action: 'client_history_delete',
+		action: 'client_core_history_delete',
 		id: line.attr('data-id')
 	},function(r){
 		line.remove();

+ 7 - 7
plugin/client/tab.home.php

@@ -106,7 +106,7 @@ Plugin::callHook('client_sheet_option',array(&$sheetOptions));
 	<h4 class="d-inline-block">Historique</h4>
 	<div class="text-left ml-3 d-inline-block noPrint text-muted">
 	   <span onclick="window.print();" class="ml-1 pointer"  title="Imprimer la page"><i class="fas fa-print"></i></span>
-	   <span onclick="client_history_search(null,true);" id="export-clients-btn" class="ml-1 pointer" title="Exporter les résultats"><i class="fas fa-file-export"></i></span>
+	   <span onclick="client_core_history_search(null,true);" id="export-clients-btn" class="ml-1 pointer" title="Exporter les résultats"><i class="fas fa-file-export"></i></span>
 	 </div>
 
 	<div class="row">
@@ -114,9 +114,9 @@ Plugin::callHook('client_sheet_option',array(&$sheetOptions));
 
 
 	    		<textarea data-type="wysiwyg" id="history-comment"></textarea>
-	    		<div class="btn btn-success mb-2" onclick="client_history_save();"><i class="fas fa-check"></i>  Enregistrer</div>
+	    		<div class="btn btn-success mb-2" onclick="client_core_history_save();"><i class="fas fa-check"></i>  Enregistrer</div>
 
-	        <select id="client-history-filters" data-type="filter" data-label="Recherche" data-function="client_history_search">
+	        <select id="client-history-filters" data-type="filter" data-label="Recherche" data-function="client_core_history_search">
 	            <option value="comment" data-filter-type="text">Libellé</option>
 	            <option value="created" data-filter-type="date">Date</option>
 	            <option value="creator" data-filter-type="user">Auteur</option>
@@ -127,7 +127,7 @@ Plugin::callHook('client_sheet_option',array(&$sheetOptions));
 	<div class="row">
 		<!-- search results -->
 		<div class="col-xl-12 client-history">
-			<ul id="historys" data-entity-search="client_history_search">
+			<ul id="historys" data-entity-search="client_core_history_search">
 				<li class="hidden item-line" data-id="{{id}}">
 					<div class="d-inline-block client-history-date">
 						{{created.dayShortName}}
@@ -136,14 +136,14 @@ Plugin::callHook('client_sheet_option',array(&$sheetOptions));
 					</div>
 					<div class="d-inline-block client-history-content">
 						<div class="w-100 text-right client-history-author">
-							 <img src="action.php?action=account_avatar_download&amp;user={{creator.login}}&amp;extension=jpg" class="avatar-mini avatar-rounded avatar-login" title="{{creator.fullName}}"> 
+							 <img src="action.php?action=core_account_avatar_download&amp;user={{creator.login}}&amp;extension=jpg" class="avatar-mini avatar-rounded avatar-login" title="{{creator.fullName}}"> 
 							<small>{{created.time}}</small>
 						</div>
 						{{{comment}}}
 						{{#editable}}
 						<ul class="client-history-options">
 							<li><i class="fas fa-pen" onclick="client_history_edit(this)"></i></li>
-							<li><i class="fas fa-trash" onclick="client_history_delete(this)"></i></li>
+							<li><i class="fas fa-trash" onclick="client_core_history_delete(this)"></i></li>
 						</ul>
 						{{/editable}}
 					</div>
@@ -152,7 +152,7 @@ Plugin::callHook('client_sheet_option',array(&$sheetOptions));
 	        <br>
 	        <!-- Pagination (data-range définit le nombre de pages max affichées avant et après la page courante) -->
 	        <ul class="pagination justify-content-center"  data-range="5">
-	            <li class="page-item hidden" data-value="{{value}}" title="Voir la page {{label}}" onclick="$(this).parent().find('li').removeClass('active');$(this).addClass('active');client_history_search();">
+	            <li class="page-item hidden" data-value="{{value}}" title="Voir la page {{label}}" onclick="$(this).parent().find('li').removeClass('active');$(this).addClass('active');client_core_history_search();">
 	                <span class="page-link">{{label}}</span>
 	            </li>
 	        </ul>

+ 1 - 1
plugin/clientmap/app.json

@@ -3,7 +3,7 @@
 	"name": "Carte des clients",
 	"author" : {
 		"name" : "Jean CARRUESCO",
-		"mail" : "jcarruesco@sys1.fr"
+		"mail" : "contact@idleman.fr"
 	},
 	"version": "1.0",
 	"url": "http://no-url.com",

+ 1 - 0
plugin/contact/action.php

@@ -42,6 +42,7 @@
 			}
 		}
 
+		$response['rows'] = array();
 		foreach($contactpersons as $contactperson){
 			$row = $contactperson->toArray();
 			$row['civility'] = ContactPerson::civilities($row['civility']); 

+ 1 - 1
plugin/contact/page.sheet.contact.person.php

@@ -8,7 +8,7 @@ if($contactperson->id==''){
 	$contactperson->uid="";
 }else{
 	$contactperson->uid = empty($contactperson->uid) ? $contactperson->id: $contactperson->uid;
-	foreach (Contact::loadAll(array('scope'=>'contact_person','uid'=>$contactperson->uid)) as $key => $contact) {
+	foreach (Contact::loadAll(array('scope'=>'contact_person','uid'=>$contactperson->id)) as $key => $contact) {
 		$contacts[]= array(
 			'type'=>$contact->type,
 			'value'=>$contact->value,

+ 277 - 321
plugin/dashboard/action.php

@@ -1,252 +1,221 @@
 <?php
-global $_,$conf;
-switch($_['action']){
+
+
 	/** DASHBOARD **/
 	//Récuperation d'une liste de dashboard
-	case 'dashboard_dashboard_search':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','read');
-			require_once(__DIR__.SLASH.'Dashboard.class.php');
-
-			$filters = array();
-			if(!$myUser->can('dashboard','configure')) $filters['creator'] = $myUser->login;
-
-			foreach(Dashboard::loadAll($filters,array('label','creator')) as $dashboard){
-				$userName = User::byLogin($dashboard->user)->fullName();
-				$dashboard->user = !empty($userName) ? $userName : $dashboard->user;
-				$dashboard->mandatory = $dashboard->mandatory == 1;
-				$dashboard->default = $dashboard->default == 1;
-				$response['rows'][] = $dashboard;
-			}
-		});
-	break;
+	Action::register('dashboard_dashboard_search',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','read');
+		require_once(__DIR__.SLASH.'Dashboard.class.php');
+
+		$filters = array();
+		if(!$myUser->can('dashboard','configure')) $filters['creator'] = $myUser->login;
+
+		foreach(Dashboard::loadAll($filters,array('label','creator')) as $dashboard){
+			$userName = User::byLogin($dashboard->user)->fullName();
+			$dashboard->user = !empty($userName) ? $userName : $dashboard->user;
+			$dashboard->mandatory = $dashboard->mandatory == 1;
+			$dashboard->default = $dashboard->default == 1;
+			$response['rows'][] = $dashboard;
+		}
+	});
 
 	//Ajout ou modification d'élément dashboard
-	case 'dashboard_dashboard_save':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			if($_['mandatory']==1 && !$myUser->can('dashboard','configure'))  throw new Exception("Vous n'avez pas les droits pour rendre ce dashboard obigatoire",403);
-			require_once(__DIR__.SLASH.'Dashboard.class.php');
-
-			$item = Dashboard::provide();
-			if(!isset($_['user']) || empty($_['user'])) $_['user'] = $myUser->login;
-
-			if($myUser->login!=$item->creator && !$myUser->can('dashboard','configure') && $item->id!=0)  throw new Exception("Vous n'avez pas les droits pour éditer le dashboard d'un autre utilisateur",403);
-			if($myUser->login!=$_['user'] && !$myUser->can('dashboard','configure')) throw new Exception("Vous n'avez pas les droits pour créer un dashboard à un autre utilisateur");
-
-			$item->user = $_['user'];
-			$item->label = $_['label'];
-			$item->icon = $_['icon'];
-			$item->default = $_['default'];
-			if($item->default) Dashboard::change(array('default'=>0), array('user'=>$item->user));
-			$item->mandatory = $_['mandatory'];
-			if($item->mandatory) Dashboard::change(array('mandatory'=>0));
-			$item->save();
-		});
-	break;
+	Action::register('dashboard_dashboard_save',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		if($_['mandatory']==1 && !$myUser->can('dashboard','configure'))  throw new Exception("Vous n'avez pas les droits pour rendre ce dashboard obigatoire",403);
+		require_once(__DIR__.SLASH.'Dashboard.class.php');
+
+		$item = Dashboard::provide();
+		if(!isset($_['user']) || empty($_['user'])) $_['user'] = $myUser->login;
+
+		if($myUser->login!=$item->creator && !$myUser->can('dashboard','configure') && $item->id!=0)  throw new Exception("Vous n'avez pas les droits pour éditer le dashboard d'un autre utilisateur",403);
+		if($myUser->login!=$_['user'] && !$myUser->can('dashboard','configure')) throw new Exception("Vous n'avez pas les droits pour créer un dashboard à un autre utilisateur");
+
+		$item->user = $_['user'];
+		$item->label = $_['label'];
+		$item->icon = $_['icon'];
+		$item->default = $_['default'];
+		if($item->default) Dashboard::change(array('default'=>0), array('user'=>$item->user));
+		$item->mandatory = $_['mandatory'];
+		if($item->mandatory) Dashboard::change(array('mandatory'=>0));
+		$item->save();
+	});
 
 	//Récuperation ou edition d'élément dashboard
-	case 'dashboard_dashboard_edit':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			require_once(__DIR__.SLASH.'Dashboard.class.php');
-			$response = Dashboard::getById($_['id']);
-		});
-	break;
+	Action::register('dashboard_dashboard_edit',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		require_once(__DIR__.SLASH.'Dashboard.class.php');
+		$response = Dashboard::getById($_['id']);
+	});
 
 	//Suppression d'élement dashboard
-	case 'dashboard_dashboard_delete':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','delete');
-			require_once(__DIR__.SLASH.'Dashboard.class.php');
-			$item = Dashboard::provide();
-			if($myUser->login!=$item->creator && !$myUser->can('dashboard','configure'))  throw new Exception("Vous n'avez pas les droits pour supprimer le dashboard d'un autre utilisateur",403);
-
-			Dashboard::deleteById($_['id']);
-
-		});
-	break;
+	Action::register('dashboard_dashboard_delete',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','delete');
+		require_once(__DIR__.SLASH.'Dashboard.class.php');
+		$item = Dashboard::provide();
+		if($myUser->login!=$item->creator && !$myUser->can('dashboard','configure'))  throw new Exception("Vous n'avez pas les droits pour supprimer le dashboard d'un autre utilisateur",403);
+		Dashboard::deleteById($_['id']);
+	});
 
 	//Sauvegarde des configurations de dashboard
-	case 'dashboard_setting_save':
-		Action::write(function(&$response){
-			global $myUser,$_,$conf;
-			User::check_access('dashboard','configure');
-			foreach(Configuration::setting('dashboard') as $key=>$value){
-				if(!is_array($value)) continue;
-				$allowed[] = $key;
-			}
-			foreach ($_['fields'] as $key => $value)
-				if(in_array($key, $allowed)) $conf->put($key,$value);
-		});
-	break;
+	Action::register('dashboard_setting_save',function(&$response){
+		global $myUser,$_,$conf;
+		User::check_access('dashboard','configure');
+		foreach(Configuration::setting('dashboard') as $key=>$value){
+			if(!is_array($value)) continue;
+			$allowed[] = $key;
+		}
+		foreach ($_['fields'] as $key => $value)
+			if(in_array($key, $allowed)) $conf->put($key,$value);
+	});
 
 	/** DASHBOARDWIDGET **/
 	//Récuperation d'une liste de dashboardwidget
-	case 'dashboard_dashboardwidget_search':
-		Action::write(function(&$response){
-			global $myUser,$myFirm,$_;
-			User::check_access('dashboard','read');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-			require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-
-			$models = DashboardWidget::models();
-			$ranksId = $myUser->getRanksId($myFirm->id);
-			$widgetsQry = "SELECT {{table}}.*,ds.mandatory,ds.sort as sort
-				FROM {{table}}
-				LEFT JOIN ".DashboardWidgetShare::tableName()." ds ON ds.widget={{table}}.id
-				WHERE dashboard=?
-					OR {{table}}.id IN (
-						SELECT widget FROM ".DashboardWidgetShare::tableName()." WHERE (entity=? AND uid=?) OR (entity=? and uid IN (".str_repeat('?,', count($ranksId) - 1) . '?'.")) OR (entity IS NULL)
-					)
-					ORDER BY sort, position DESC";
-			$widgets = DashboardWidget::staticQuery($widgetsQry,array_merge(array($_['dashboard'],'user',$myUser->login,'rank'),$ranksId),true);
-
-			foreach($widgets as $widget){
-				if(!isset($models[$widget->model])) continue;
-				$model = clone $models[$widget->model];
-
-				$row = $model->toArray();
-				$row['id'] = $widget->id;
-				$row['width'] = !empty($widget->width) && $widget->width>0 ? $widget->width : $model->defaultWidth;
-				$row['position'] = $widget->position;
-				$row['minified'] = $widget->minified;
-				$row['dashboard'] = $widget->dashboard;
-
-				if(!empty($widget->foreign('mandatory'))) $row['mandatory'] = $widget->foreign('mandatory');
-				if(!empty($widget->foreign('sort'))) $row['position'] = $widget->foreign('sort');
-
-				$response['rows'][] = $row;
-			}
-
-			if(isset($response['rows'])){
-				usort($response['rows'],function($a,$b){
-					return $a['position'] - $b['position'];
-				});
-			}
-
-		});
-	break;
+	Action::register('dashboard_dashboardwidget_search',function(&$response){
+	
+		global $myUser,$myFirm,$_;
+		User::check_access('dashboard','read');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
+
+		$models = DashboardWidget::models();
+		$ranksId = $myUser->getRanksId($myFirm->id);
+		$widgetsQry = "SELECT {{table}}.*,ds.mandatory,ds.sort as sort
+			FROM {{table}}
+			LEFT JOIN ".DashboardWidgetShare::tableName()." ds ON ds.widget={{table}}.id
+			WHERE dashboard=?
+				OR {{table}}.id IN (
+					SELECT widget FROM ".DashboardWidgetShare::tableName()." WHERE (entity=? AND uid=?) OR (entity=? and uid IN (".str_repeat('?,', count($ranksId) - 1) . '?'.")) OR (entity IS NULL)
+				)
+				ORDER BY sort, position DESC";
+		$widgets = DashboardWidget::staticQuery($widgetsQry,array_merge(array($_['dashboard'],'user',$myUser->login,'rank'),$ranksId),true);
+
+		foreach($widgets as $widget){
+			if(!isset($models[$widget->model])) continue;
+			$model = clone $models[$widget->model];
+
+			$row = $model->toArray();
+			$row['id'] = $widget->id;
+			$row['width'] = !empty($widget->width) && $widget->width>0 ? $widget->width : $model->defaultWidth;
+			$row['position'] = $widget->position;
+			$row['minified'] = $widget->minified;
+			$row['dashboard'] = $widget->dashboard;
+
+			if(!empty($widget->foreign('mandatory'))) $row['mandatory'] = $widget->foreign('mandatory');
+			if(!empty($widget->foreign('sort'))) $row['position'] = $widget->foreign('sort');
+
+			$response['rows'][] = $row;
+		}
+
+		if(isset($response['rows'])){
+			usort($response['rows'],function($a,$b){
+				return $a['position'] - $b['position'];
+			});
+		}
+	});
 
 	//Ajout ou modification d'élément dashboardwidget
-	case 'dashboard_dashboardwidget_save':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
-			$item = DashboardWidget::provide();
-			$item->model = $_['model'];
-			$item->data = $_['data'];
-			$item->position = $_['position'];
-			$item->minified = $_['minified'];
-			$item->dashboard = $_['dashboard'];
-			$item->save();
-		});
-	break;
+	Action::register('dashboard_dashboardwidget_save',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$item = DashboardWidget::provide();
+		$item->model = $_['model'];
+		$item->data = $_['data'];
+		$item->position = $_['position'];
+		$item->minified = $_['minified'];
+		$item->dashboard = $_['dashboard'];
+		$item->save();
+	});
 
 	//Récuperation ou edition d'élément dashboardwidget
-	case 'dashboard_dashboardwidget_edit':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-			$response = DashboardWidget::getById($_['id']);
-		});
-	break;
+	Action::register('dashboard_dashboardwidget_edit',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$response = DashboardWidget::getById($_['id']);
+	});
 
 	//Suppression d'élement dashboardwidget
-	case 'dashboard_dashboardwidget_delete':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','delete');
-			require_once(__DIR__.SLASH.'Dashboard.class.php');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
-			$widget = DashboardWidget::getById($_['widget']);
-			if(!$widget) return;
+	Action::register('dashboard_dashboardwidget_delete',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','delete');
+		require_once(__DIR__.SLASH.'Dashboard.class.php');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$widget = DashboardWidget::getById($_['widget']);
+		if(!$widget) return;
 
-			$dashboard = Dashboard::getById($_['dashboard']);
-			if($widget->dashboard!=$dashboard->id || $dashboard->user!=$myUser->login)
-				throw new Exception("Vous ne pouvez supprimer que vos propres widgets");
+		$dashboard = Dashboard::getById($_['dashboard']);
+		if($widget->dashboard!=$dashboard->id || $dashboard->user!=$myUser->login)
+			throw new Exception("Vous ne pouvez supprimer que vos propres widgets");
 
-			$widget->deleteById($widget->id);
-			$response['message'] = 'Widget supprimé';
-		});
-	break;
+		$widget->deleteById($widget->id);
+		$response['message'] = 'Widget supprimé';
+	});
 
 	//Resize largeur d'élement dashboardwidget
-	case 'dashboard_dashboardwidget_resize':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			require_once(__DIR__.SLASH.'Dashboard.class.php');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-			User::check_access('dashboard','edit');
-
-			$widget = DashboardWidget::getById($_['widget']);
-			$dashboard = Dashboard::getById($widget->dashboard);
-			if($widget->dashboard!=$dashboard->id || $dashboard->user!=$myUser->login)
-				throw new Exception("Vous ne pouvez redimenssioner que vos propres widgets");
-
-			$widget->width = $_['width'];
-			$widget->save();
-		});
-	break;
-
-	case 'dashboard_dashboardwidget_refresh':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','read');
-			$widgets = array();
-			Plugin::callHook('widget_refresh',array(&$widgets));
-			$response['rows'] = $widgets;
-		});
-	break;
-
-	case 'dashboard_dashboardwidget_add':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
-			$widget = new DashboardWidget();
-			$widget->model = $_['widget'];
-			$widget->position = 666;
-			$widget->minified = false;
-			$widget->width = $widget->width> 0 ? $widget->width: $widget->defaultWidth ;
-			$widget->dashboard = $_['dashboard'];
-			$widget->save();
-			$response['message'] = 'Widget ajouté';
-		});
-	break;
-
-	case 'dashboard_dashboardwidget_save_position':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			require_once(__DIR__.SLASH.'Dashboard.class.php');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-			$dashboard = Dashboard::getById($_['dashboard']);
-
-			if($dashboard->user!=$myUser->login) throw new Exception("Vous ne pouvez modifier que vos propres widgets");
-			$dashboard_widgets = DashboardWidget::loadAll( array('dashboard' => $dashboard->id ) );
-
-			foreach($_['positions'] as $move){
-				foreach($dashboard_widgets as $dashboard_widget){
-					if($dashboard_widget->id!=$move['id']) continue;
-					$dashboard_widget->position = $move['position'];
-					$dashboard_widget->save();
-				}
+	Action::register('dashboard_dashboardwidget_resize',function(&$response){
+		global $myUser,$_;
+		require_once(__DIR__.SLASH.'Dashboard.class.php');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		User::check_access('dashboard','edit');
+
+		$widget = DashboardWidget::getById($_['widget']);
+		$dashboard = Dashboard::getById($widget->dashboard);
+		if($widget->dashboard!=$dashboard->id || $dashboard->user!=$myUser->login)
+			throw new Exception("Vous ne pouvez redimenssioner que vos propres widgets");
+
+		$widget->width = $_['width'];
+		$widget->save();
+	});
+
+	Action::register('dashboard_dashboardwidget_refresh',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','read');
+		$widgets = array();
+		Plugin::callHook('widget_refresh',array(&$widgets));
+		$response['rows'] = $widgets;
+	});
+
+	Action::register('dashboard_dashboardwidget_add',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$widget = new DashboardWidget();
+		$widget->model = $_['widget'];
+		$widget->position = 666;
+		$widget->minified = false;
+		$widget->width = $widget->width> 0 ? $widget->width: $widget->defaultWidth ;
+		$widget->dashboard = $_['dashboard'];
+		$widget->save();
+		$response['message'] = 'Widget ajouté';
+	});
+
+	Action::register('dashboard_dashboardwidget_save_position',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		require_once(__DIR__.SLASH.'Dashboard.class.php');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$dashboard = Dashboard::getById($_['dashboard']);
+
+		if($dashboard->user!=$myUser->login) throw new Exception("Vous ne pouvez modifier que vos propres widgets");
+		$dashboard_widgets = DashboardWidget::loadAll( array('dashboard' => $dashboard->id ) );
+
+		foreach($_['positions'] as $move){
+			foreach($dashboard_widgets as $dashboard_widget){
+				if($dashboard_widget->id!=$move['id']) continue;
+				$dashboard_widget->position = $move['position'];
+				$dashboard_widget->save();
 			}
-		});
-	break;
+		}
+	});
 
 	/* CLOCK */
-	case 'dashboard_widget_clock_load':
+	Action::register('dashboard_widget_clock_load',function(&$response){
 		global $myUser;
 		User::check_access('dashboard','read');
 		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
@@ -254,12 +223,12 @@ switch($_['action']){
 		ob_start();
 		require_once(__DIR__.SLASH.'widget.clock.php');
 		$widget->content = ob_get_clean();
-
 		echo json_encode($widget);
-	break;
+		exit;
+	});
 
 	/* LOGS */
-	case 'dashboard_widget_log_load':
+	Action::register('dashboard_widget_log_load',function(&$response){
 		global $myUser;
 		require_once('DashboardWidget.class.php');
 		User::check_access('log','read');
@@ -271,10 +240,11 @@ switch($_['action']){
 		require_once(__DIR__.SLASH.'widget.logs.php');
 		$widget->content = ob_get_clean();
 		echo json_encode($widget);
-	break;
+		exit;
+	});
 
 	/* PROFILE */
-	case 'dashboard_widget_profile_load':
+	Action::register('dashboard_widget_profile_load',function(&$response){
 		global $myUser;
 		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
 		User::check_access('dashboard','read');
@@ -283,11 +253,11 @@ switch($_['action']){
 		ob_start();
 		require_once(__DIR__.SLASH.'widget.profile.php');
 		$widget->content = ob_get_clean();
-
 		echo json_encode($widget);
-	break;
+		exit;
+	});
 
-	case 'dashboard_widget_profile_configure':
+	Action::register('dashboard_widget_profile_configure',function(&$response){
 		global $myUser;
 		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
 		User::check_access('dashboard','read');
@@ -297,22 +267,21 @@ switch($_['action']){
 		$content = ob_get_clean();
 
 		echo $content ;
-	break;
+		exit;
+	});
 
-	case 'dashboard_widget_profile_configure_save':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','read');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-			$widget = DashboardWidget::getById($_['id']);
-			$widget->data('background-color',$_['widget-profile-background-color']);
-			$widget->save();
-		});
-	break;
+	Action::register('dashboard_widget_profile_configure_save',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','read');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$widget = DashboardWidget::getById($_['id']);
+		$widget->data('background-color',$_['widget-profile-background-color']);
+		$widget->save();
+	});
 
 
 	/* HTML */
-	case 'dashboard_widget_html_load':
+	Action::register('dashboard_widget_html_load',function(&$response){
 		global $myUser;
 		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
 		User::check_access('dashboard','read');
@@ -322,104 +291,91 @@ switch($_['action']){
 		ob_start();
 		require_once(__DIR__.SLASH.'widget.html.php');
 		$widget->content = ob_get_clean();
-
 		echo json_encode($widget);
-	break;
+		exit;
+	});
 
-	case 'dashboard_widget_html_configure':
+	Action::register( 'dashboard_widget_html_configure',function(&$response){
 		global $myUser;
 		User::check_access('dashboard','read');
 		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
 		$widget = DashboardWidget::current();
 		ob_start();
 		require_once(__DIR__.SLASH.'widget.html.configure.php');
 		$content = ob_get_clean();
-
 		echo $content ;
-	break;
-
-	case 'dashboard_widget_html_configure_save':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','read');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-			$widget = DashboardWidget::getById($_['id']);
-			$widget->data('html',html_entity_decode($_['widget-html-content']));
-			$widget->data('title',$_['widget-html-title']);
-			$widget->data('color',$_['widget-html-color']);
-			$widget->save();
-		});
-	break;
+		exit;
+	});
+
+	Action::register('dashboard_widget_html_configure_save',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','read');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$widget = DashboardWidget::getById($_['id']);
+		$widget->data('html',html_entity_decode($_['widget-html-content']));
+		$widget->data('title',$_['widget-html-title']);
+		$widget->data('color',$_['widget-html-color']);
+		$widget->save();
+	});
 
 	/* DASHBOARD SHARE */
 	/** DASHBOARDWIDGETSHARE **/
 	//Récuperation d'une liste de dashboardwidgetshare
-	case 'dashboard_widget_share_search':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','read');
-			require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
-
-			$dashboardwidgetshares = DashboardWidgetShare::loadAll(array(), null,  null,array('*'), 1);
-			foreach($dashboardwidgetshares as $dashboardwidgetshare){
-				$row = $dashboardwidgetshare->toArray();
-
-				$row['widget'] = $dashboardwidgetshare->join('widget')->toArray();
-				$row['for'] = 'Tout le monde';
-				if($row['entity'] == 'rank' ) $row['for'] = 'Rang: '. Rank::getById($row['uid'] )->label;
-				if($row['entity'] == 'user' ) $row['for'] ='Utilisateur: '. User::byLogin($row['uid'] )->fullName();
-				$response['rows'][] = $row;
-			}
-		});
-	break;
+	Action::register('dashboard_widget_share_search',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','read');
+		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+
+		$dashboardwidgetshares = DashboardWidgetShare::loadAll(array(), null,  null,array('*'), 1);
+		foreach($dashboardwidgetshares as $dashboardwidgetshare){
+			$row = $dashboardwidgetshare->toArray();
+
+			$row['widget'] = $dashboardwidgetshare->join('widget')->toArray();
+			$row['for'] = 'Tout le monde';
+			if($row['entity'] == 'rank' ) $row['for'] = 'Rang: '. Rank::getById($row['uid'] )->label;
+			if($row['entity'] == 'user' ) $row['for'] ='Utilisateur: '. User::byLogin($row['uid'] )->fullName();
+			$response['rows'][] = $row;
+		}
+	});
 
 	//Ajout ou modification d'élément dashboardwidgetshare
-	case 'dashboard_widget_share_save':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-			//DashboardWidgetShare::create();
-			$item = DashboardWidgetShare::provide();
-
-			if(!isset( $_['widget']) || !is_numeric($_['widget'])) throw new Exception("Widget non spécifié ou invalide");
-
-			$item->widget = $_['widget'];
-			$item->mandatory = 1;//$_['mandatory'];
-
-			if(isset($_['entity'])){
-				$item->entity = $_['entity'];
-				$item->uid = $_['uid'];
-			}
-			$item->sort = !isset($_['sort']) ? 0 : $_['sort'];
-			$item->save();
-		});
-	break;
+	Action::register('dashboard_widget_share_save',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
+		//DashboardWidgetShare::create();
+		$item = DashboardWidgetShare::provide();
 
+		if(!isset( $_['widget']) || !is_numeric($_['widget'])) throw new Exception("Widget non spécifié ou invalide");
+
+		$item->widget = $_['widget'];
+		$item->mandatory = 1;//$_['mandatory'];
+
+		if(isset($_['entity'])){
+			$item->entity = $_['entity'];
+			$item->uid = $_['uid'];
+		}
+		$item->sort = !isset($_['sort']) ? 0 : $_['sort'];
+		$item->save();
+	});
 
-	//Récuperation ou edition d'élément dashboardwidgetshare
-	case 'dashboard_widget_share_edit':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','edit');
-			require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-			require_once(__DIR__.SLASH.'DashboardWidget.class.php');
 
-			$response = DashboardWidgetShare::getById($_['id'],1)->toArray();
-		});
-	break;
+	//Récuperation ou edition d'élément dashboardwidgetshare
+	Action::register('dashboard_widget_share_edit',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','edit');
+		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
+		require_once(__DIR__.SLASH.'DashboardWidget.class.php');
+		$response = DashboardWidgetShare::getById($_['id'],1)->toArray();
+	});
 
 	//Suppression d'élement dashboardwidgetshare
-	case 'dashboard_widget_share_delete':
-		Action::write(function(&$response){
-			global $myUser,$_;
-			User::check_access('dashboard','delete');
-			require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
-
-			DashboardWidgetShare::deleteById($_['id']);
-		});
-	break;
-}
+	Action::register('dashboard_widget_share_delete',function(&$response){
+		global $myUser,$_;
+		User::check_access('dashboard','delete');
+		require_once(__DIR__.SLASH.'DashboardWidgetShare.class.php');
+		DashboardWidgetShare::deleteById($_['id']);
+	});
+
 ?>

+ 4 - 5
plugin/dashboard/dashboard.plugin.php

@@ -28,10 +28,9 @@ function dashboard_uninstall($id){
 Right::register('dashboard',array('label'=>'Gestion des droits sur le plugin dashboard'));
 
 
-//cette fonction comprends toutes les actions du plugin qui ne nécessitent pas de vue html
-function dashboard_action(){
-	require_once(__DIR__.SLASH.'action.php');
-}
+//Comprends toutes les actions du plugin qui ne nécessitent pas de vue html
+require_once(__DIR__.SLASH.'action.php');
+
 
 //Déclaration du menu de réglages
 function dashboard_menu_setting(&$settingMenu){
@@ -127,7 +126,7 @@ Plugin::addHook("uninstall", "dashboard_uninstall");
 
 
 Plugin::addHook("page", "dashboard_page");  
-Plugin::addHook("action", "dashboard_action");  
+
 Plugin::addHook("menu_setting", "dashboard_menu_setting");    
 Plugin::addHook("content_setting", "dashboard_content_setting");   
 Plugin::addHook("widget", "dashboard_default_widget");

+ 37 - 55
plugin/directory/action.php

@@ -1,53 +1,41 @@
 <?php
-global $_,$conf;
-switch($_['action']){
 
 	/** SMS **/
-
 	//Envois d'un contact par sms
-	case 'directory_send_sms':
-		Action::write(function(&$response){
-			global $myUser,$_,$conf;
-			if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
-			
-			Plugin::need('sms/Sms');
-
-			$user = User::byLogin($_['user']);
-			if(empty($myUser->mobile))throw new Exception("Votre numéro de téléphone n'est pas renseigné");
-
-
-			if(empty($conf->get('sms_api_url')) || empty($conf->get('sms_api_token'))) throw new Exception("Api SMS non configurée");
-			
-			$sms = new Sms($conf->get('sms_api_url'),$conf->get('sms_api_token'));
-			$sms->phone = str_replace(' ','',$myUser->mobile);
-
-			$card = ROOT_URL.'/action.php?action=directory_get_cardav&token='.sha1('vcard:'.$user->phone.'-'.$user->id.'-'.$user->login);
-			$sms->message = $user->fullName().': ';
-			$sms->message .= PHP_EOL;
-			$sms->message .= 'fixe : '.str_replace(' ','',$user->phone);
-			$sms->message .= PHP_EOL;
-			$sms->message .= 'mobile : '.str_replace(' ','',$user->mobile);
-			$sms->message .= PHP_EOL;
-			$sms->message .= 'mail : '.$user->mail;
-			$sms->message .= PHP_EOL;
-			$sms->message .=' vcard: '.$card;
-
-			Log::put('Envois à '.$sms->phone.' : '.$sms->message,'Sms');
-			try{
-				$response = $sms->send();
-				Log::put('Envois à '.$sms->phone.' : '.json_encode($response),'Sms');
-				$response['phone'] = $myUser->mobile;
-			}catch(Exception $e){
-				throw new Exception('ERREUR : '.$e->getMessage());
-				Log::put('Envois à '.$sms->phone.' ERREUR : '.$e->getMessage(),'Sms');
-			}
-
-
-		});
-	break;
+	Action::register('directory_send_sms',function(&$response){
+		global $myUser,$_,$conf;
+		if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
+		Plugin::need('sms/Sms');
+		$user = User::byLogin($_['user']);
+		if(empty($myUser->mobile))throw new Exception("Votre numéro de téléphone n'est pas renseigné");
+		if(empty($conf->get('sms_api_url')) || empty($conf->get('sms_api_token'))) throw new Exception("Api SMS non configurée");
+		$sms = new Sms($conf->get('sms_api_url'),$conf->get('sms_api_token'));
+		$sms->phone = str_replace(' ','',$myUser->mobile);
+
+		$card = ROOT_URL.'/action.php?action=directory_get_cardav&token='.sha1('vcard:'.$user->phone.'-'.$user->id.'-'.$user->login);
+		$sms->message = $user->fullName().': ';
+		$sms->message .= PHP_EOL;
+		$sms->message .= 'fixe : '.str_replace(' ','',$user->phone);
+		$sms->message .= PHP_EOL;
+		$sms->message .= 'mobile : '.str_replace(' ','',$user->mobile);
+		$sms->message .= PHP_EOL;
+		$sms->message .= 'mail : '.$user->mail;
+		$sms->message .= PHP_EOL;
+		$sms->message .=' vcard: '.$card;
+
+		Log::put('Envois à '.$sms->phone.' : '.$sms->message,'Sms');
+		try{
+			$response = $sms->send();
+			Log::put('Envois à '.$sms->phone.' : '.json_encode($response),'Sms');
+			$response['phone'] = $myUser->mobile;
+		}catch(Exception $e){
+			throw new Exception('ERREUR : '.$e->getMessage());
+			Log::put('Envois à '.$sms->phone.' ERREUR : '.$e->getMessage(),'Sms');
+		}
+	});
 	
 
-	case 'directory_get_qr':
+	Action::register('directory_get_qr',function(&$response){
 		global $myUser,$_,$conf;
 		if(!$myUser->connected()) throw new Exception("Permission denied");
 		header('Content-type:image/gif');
@@ -56,9 +44,9 @@ switch($_['action']){
 		$a = new QR($meCard);
 		echo $a->image(7);
 		exit();
-		break;
+	});
 
-	case 'directory_get_cardav':
+	Action::register('directory_get_cardav',function(&$response){
 		global $myUser,$_,$conf;
 		if(!$myUser->connected()) throw new Exception("Permission denied");
 		if(isset($_['token'])){
@@ -74,7 +62,6 @@ switch($_['action']){
 		header('Content-Type: text/x-vCard');
 		header('Content-Disposition: attachment; filename= "'.$user->login.'.vcf"');  
 
-
 		$vCard =  'BEGIN:VCARD'.PHP_EOL;
 		$vCard .= 'VERSION:3.0'.PHP_EOL;
 		$vCard .= 'N:'.utf8_decode($user->name.';'.$user->firstname).PHP_EOL;
@@ -88,9 +75,9 @@ switch($_['action']){
 		header('Content-Length: '.strlen($vCard)); 
 		echo $vCard;
 		exit();
-	break;
+	});
 
-	case 'directory_get_excel':
+	Action::register('directory_get_excel',function(&$response){
 		global $myUser,$_,$conf;
 		if(!$myUser->connected()) throw new Exception("Permission denied");
 		
@@ -106,11 +93,6 @@ switch($_['action']){
 		File::downloadStream($excel,"annuaire ".date('d-m-Y').".csv",'text/csv');
 
 		exit();
-	break;
-
-
-	
-
+	});
 
-}
 ?>

+ 4 - 5
plugin/directory/directory.plugin.php

@@ -46,9 +46,9 @@ function directory_get_contacts(){
 }
 
 //cette fonction comprends toutes les actions du plugin qui ne nécessitent pas de vue html
-function directory_action(){
-	require_once(__DIR__.SLASH.'action.php');
-}
+
+require_once(__DIR__.SLASH.'action.php');
+
 
 
 function directory_plugin_page(){
@@ -106,8 +106,7 @@ function directory_plugin_page(){
 
 
 Plugin::addJs("/js/main.js");
- 
-Plugin::addHook("action", "directory_action");  
+
 Plugin::addHook("menu_account", "directory_plugin_menu");  
 Plugin::addHook("content_account", "directory_plugin_page"); 
 

+ 5 - 5
plugin/docker/Ovh.class.php

@@ -17,7 +17,7 @@ class Ovh{
             "path": "/*"
         }
     ],
-    "redirection":"https://www.sys1.fr/"
+    "redirection":"https://www.idleman.fr/"
 }';
         $headers = array();
        
@@ -27,7 +27,7 @@ class Ovh{
     }
 
     public function domain(){
-       return $this->rest('GET','/1.0/domain/zone/sys1.fr/record/5136453749','');
+       return $this->rest('GET','/1.0/domain/zone/idleman.fr/record/5136453749','');
     }
 
     public function getDomain($zone = ''){
@@ -40,13 +40,13 @@ class Ovh{
          $body = array(
             'fieldType' =>  'CNAME',
             'subDomain' =>  $subdomain,
-            'target' =>  'sys1.fr.',
+            'target' =>  'idleman.fr.',
             'ttl' =>  '0'
          );
         
 
-        $response =  $this->rest('POST','/1.0/domain/zone/sys1.fr/record',json_encode($body));
-        $this->rest('POST','/1.0/domain/zone/sys1.fr/refresh');
+        $response =  $this->rest('POST','/1.0/domain/zone/idleman.fr/record',json_encode($body));
+        $this->rest('POST','/1.0/domain/zone/idleman.fr/refresh');
        return $response;
     }
 

+ 1 - 1
plugin/docker/action.php

@@ -378,7 +378,7 @@
 			if(isset($existingDomains['message'])) throw new Exception("Erreur de creation : ".$existingDomains['message']);
 			
 		
-			//ex pour test.sys1.biz CNAME vers docker-wordpress.sys1.fr => 'sys1.byz','test','docker-wordpress.sys1.fr'
+			//ex pour test.kiss.biz CNAME vers docker-wordpress.kiss.fr => 'kiss.byz','test','docker-wordpress.kiss.fr'
 			$response = $ovh->setDomain($domain,$subdomain,$machine->domain);
 
 			//$response = $ovh->domain();

+ 3 - 3
plugin/docker/docker.plugin.php

@@ -33,8 +33,8 @@ function docker_install($id){
 	global $conf;
 	
 	$conf->get('docker_ovh_host','https://eu.api.ovh.com');
-	$conf->get('docker_git_host','http://git.sys1.fr/api/v4');
-	$conf->get('docker_sophos_host','https://firewall.sys1.fr');
+	$conf->get('docker_git_host','http://git.idleman.fr/api/v4');
+	$conf->get('docker_sophos_host','https://firewall.idleman.fr');
 	$conf->get('docker_sophos_port','4444');
 
 
@@ -90,7 +90,7 @@ Configuration::setting('docker',array(
         'docker_ovh_application_secret' => array("label"=>"Clé privée d'application","type"=>"password"),
         'docker_ovh_consumer_key' => array("label"=>"Clé consommateur","type"=>"password"),
         "GitLab",
-        'docker_git_host' => array("label"=>"Hote gitlab","placeholder"=>'ex: http://git.sys1.fr/api/v4',"type"=>"string"),
+        'docker_git_host' => array("label"=>"Hote gitlab","placeholder"=>'ex: http://git.idleman.fr/api/v4',"type"=>"string"),
         'docker_git_token' => array("label"=>"Clé privée d'application","type"=>"password"),
 ));
 

+ 1 - 1
plugin/docker/setting.global.docker.php

@@ -24,5 +24,5 @@ User::check_access('docker','configure');
 
 <p>
 	Pour récuperer l'app key et l'app secret OVH, cliquez ici : <a href="https://eu.api.ovh.com/createApp/">https://eu.api.ovh.com/createApp/</a>
-	Puis remplissez les settings avec les infos app key et app secret, enregistrez et lancez l'action suivante : <a href="http://127.0.0.1/sys1/erp-core/action.php?action=docker_ovh_consumerKey_generate">http://127.0.0.1/sys1/erp-core/action.php?action=docker_ovh_consumerKey_generate</a>, sur l'url unique qui s'affiche, se logguer avec les identifiants OVH et saisir "unlinmited" puis cliquer sur ok
+	Puis remplissez les settings avec les infos app key et app secret, enregistrez et lancez l'action suivante : <a href="<?php echo ROOT_URL ?>/action.php?action=docker_ovh_consumerKey_generate"><?php echo ROOT_URL ?>/action.php?action=docker_ovh_consumerKey_generate</a>, sur l'url unique qui s'affiche, se logguer avec les identifiants OVH et saisir "unlinmited" puis cliquer sur ok
 </p>

+ 1 - 1
plugin/docker/tab.environment.migration.php

@@ -39,7 +39,7 @@
 					 Cryptage: Aucun <br>
 					 Port: 25 <br>
 					 Authentification: Aucun <br>
-					 Supprimer le suser sys1 si plus besoin
+					 Supprimer le suser kiss si plus besoin
 				</strong>
 					</template>
 				<code class="migrationPath"></code>

+ 2 - 4
plugin/document/Element.class.php

@@ -559,10 +559,8 @@ class Element extends Entity{
 			//si le droit n'est pas récursif et que le chemin associé n'est pas exactement cleui ciblé on ignore ce droit
 			if($line['recursive'] != 1  && $line['path']!=$element->path) continue;
 			
-			$rights = array(
-				'edit'=> $line['edit'] == 1,
-				'read'=> $line['read'] == 1
-			);
+			if($line['edit'] == 1) $rights['edit'] = true;
+			if($line['read'] == 1) $rights['read'] = true;
 			
 		}
 		

+ 1 - 0
plugin/document/WebDav.class.php

@@ -645,6 +645,7 @@ class WebDav{
 		}
 
 		if($this->logs=='') return;
+		if(!file_exists(dirname($this->logs))) mkdir(dirname($this->logs));
 		file_put_contents($this->logs, $message.PHP_EOL,FILE_APPEND);
 	}
 

+ 105 - 90
plugin/document/js/document.api.js

@@ -1,13 +1,13 @@
 
 
 
-var  DocumentApi = function(element,options) {
+var DocumentApi = function(element,options) {
 			
 			this.onEvents = {};
 			this.currentView = 'list';
 			this.currentFolder = '.';
 			this.views = [];
-			this.selected = null;
+			this.selected = [];
 			this.isProcessing = false;
 
 			this.editorOptions = {
@@ -269,7 +269,7 @@ var  DocumentApi = function(element,options) {
 					case 113:
 						if(!object.options.rightEdit) break;
 						if($('.file-view tr').hasClass('element-focused'))
-							object.element_rename_edit($('.element-rename',object.selected.element));
+							object.element_rename_edit($('.element-rename',object.selected[0].element));
 					break;
 					case 13:
 						if($('.label-search',object.dom.panels.search).is(":focus"))
@@ -463,13 +463,11 @@ var  DocumentApi = function(element,options) {
 			//EVENTS
 
 			//Prévisualisation
-			$('.file-view:visible .file-element',object.dom.panels.files).click(function(event){ object.element_preview(this, event);  });
+			$('.file-view:visible .file-element',object.dom.panels.files).off('click').click(function(event){ object.element_preview(this, event);  });
 			//Ouverture fichier / dossier
-			$('.file-view:visible .file-element',object.dom.panels.files).dblclick(function(event){ object.element_execute(this);  });
+			$('.file-view:visible .file-element',object.dom.panels.files).off('dblclick').dblclick(function(event){ object.element_execute(this);  });
 			
 
-
-			
 			//Renommage
 			$('.file-view:visible .file-element .element-rename',object.dom.panels.files).click(function(event){ 
 				event.stopPropagation();
@@ -993,117 +991,131 @@ var  DocumentApi = function(element,options) {
 		var object = this;
 		var line = $(element);
 
-		if(line.hasClass('element-focused')) return;
+		console.log('preview');
+
+		if(!event.ctrlKey) object.selected = [];
 
-		object.selected = {
+		object.selected.push({
 			element : line,
 			path : line.attr('data-path'),
 			type : line.attr('data-type'),
 			extension : line.attr('data-extension'),
 			id : line.attr('data-id')
-		}
+		});
 
-		$('.right-panel',object.dom.panels.detail).addClass('hidden');
+		console.log(object.selected);
 
-		$('.detail-buttons',object.dom.panels.detail).removeClass('hidden');
-		if(object.selected.type =='directory') {
-			$('.detail-buttons > .directory-button',object.dom.panels.detail).removeClass('hidden');
-		}else{
-			$('.detail-buttons > .directory-button',object.dom.panels.detail).addClass('hidden');
-		}  
+		$('.file-view:visible .file-element',object.dom.panels.files).removeClass('element-focused');
+			
+		for(var k in object.selected){
+			object.selected[k].element.addClass('element-focused');
+		}
 
+		if(line.hasClass('element-focused')) return;
 
+		if(object.selected.length==1){
+			$('.right-panel',object.dom.panels.detail).addClass('hidden');
+			$('.detail-buttons',object.dom.panels.detail).removeClass('hidden');
+			
 
-		$('.detail-buttons > li:visible',object.dom.panels.detail).remove();
-		var buttonTemplate = $('.detail-buttons > li:eq(0).hidden').get(0).outerHTML;
-		if(object.options.panels.detail.buttons){
-			for(var i in object.options.panels.detail.buttons){
-				var data = object.options.panels.detail.buttons[i];
-				if(data.visibility && data.visibility.type && data.visibility.type.indexOf(object.selected.type) == -1 ) continue;
-				if(data.visibility && data.visibility.extension && data.visibility.extension.indexOf(object.selected.extension) == -1 ) continue;
-				
-				var button = $(Mustache.render(buttonTemplate,data));
-				button.removeClass('hidden');
-				$('.detail-buttons').append(button);
+			if(object.selected.type =='directory') {
+				$('.detail-buttons > .directory-button',object.dom.panels.detail).removeClass('hidden');
+			}else{
+				$('.detail-buttons > .directory-button',object.dom.panels.detail).addClass('hidden');
 			}
-		}
 
-		//autoblur sur le rename d'un fichier en cours si existant
-		var currentRename = $('.file-view:visible .file-element .rename-input:visible');
-		if(currentRename.length>0) currentRename.trigger('blur');
-		
-		$('.file-view:visible .file-element',object.dom.panels.files).removeClass('element-focused');
-		line.addClass('element-focused');
+			$('.detail-buttons > li:visible',object.dom.panels.detail).remove();
+			var buttonTemplate = $('.detail-buttons > li:eq(0).hidden').get(0).outerHTML;
+			if(object.options.panels.detail.buttons){
+				for(var i in object.options.panels.detail.buttons){
+					var data = object.options.panels.detail.buttons[i];
+					if(data.visibility && data.visibility.type && data.visibility.type.indexOf(object.selected.type) == -1 ) continue;
+					if(data.visibility && data.visibility.extension && data.visibility.extension.indexOf(object.selected.extension) == -1 ) continue;
+					
+					var button = $(Mustache.render(buttonTemplate,data));
+					button.removeClass('hidden');
+					$('.detail-buttons').append(button);
+				}
+			}
 
-		$('.detail-thumbnail .thumbnail-preloader',object.dom.panels.detail).addClass('show');
+			//autoblur sur le rename d'un fichier en cours si existant
+			var currentRename = $('.file-view:visible .file-element .rename-input:visible');
+			if(currentRename.length>0) currentRename.trigger('blur');
+			
+	
 
-		$.action({
-			action : object.options.actions.element_preview,
-			path : line.attr('data-path'),
-		},function(response){
+			$('.detail-thumbnail .thumbnail-preloader',object.dom.panels.detail).addClass('show');
 
-			setTimeout(function(){
-				$('.detail-thumbnail .thumbnail-preloader',object.dom.panels.detail).removeClass('show');
-			},100);
+			$.action({
+				action : object.options.actions.element_preview,
+				path : line.attr('data-path'),
+			},function(response){
 
-			$('.detail-thumbnail',object.dom.panels.detail).css('background-image','url('+response.row.thumbnail+')');
+				setTimeout(function(){
+					$('.detail-thumbnail .thumbnail-preloader',object.dom.panels.detail).removeClass('show');
+				},100);
 
-			var substrings = ['.jpg','.jpeg','.bmp','.gif','.png','.jfif'];
-			$('.detail-thumbnail',object.dom.panels.detail).css('background-size','');
-			if (new RegExp(substrings.join("|")).test(response.row.thumbnail))
-				$('.detail-thumbnail',object.dom.panels.detail).css('background-size','contain');
+				$('.detail-thumbnail',object.dom.panels.detail).css('background-image','url('+response.row.thumbnail+')');
 
-			$('> h1',object.dom.panels.detail).html(response.row.label).text();
-			var size = response.row.sizeReadable;
-			if(response.row.type == 'directory') size = response.row.childNumber+' élement'+(response.row.childNumber>1?'s':'');
+				var substrings = ['.jpg','.jpeg','.bmp','.gif','.png','.jfif'];
+				$('.detail-thumbnail',object.dom.panels.detail).css('background-size','');
+				if (new RegExp(substrings.join("|")).test(response.row.thumbnail))
+					$('.detail-thumbnail',object.dom.panels.detail).css('background-size','contain');
 
-			$('> small > span',object.dom.panels.detail).text(size+", "+response.row.updatedRelative);
+				$('> h1',object.dom.panels.detail).html(response.row.label).text();
+				var size = response.row.sizeReadable;
+				if(response.row.type == 'directory') size = response.row.childNumber+' élement'+(response.row.childNumber>1?'s':'');
 
-			object.triggerEvent('selected',object.selected);
+				$('> small > span',object.dom.panels.detail).text(size+", "+response.row.updatedRelative);
 
-		});
+				object.triggerEvent('selected',object.selected);
+
+			});
+		}
 	}
 
 	//Suppression d'un élément de la GED
 	DocumentApi.prototype.element_delete = function(){
 
 		var object = this;
-		if($('span .rename-input:visible',object.selected.element).length) return;
-		
-		if(object.selected == null) {
-			$.message('info', 'Sélectionnez d\'abord un élément à supprimer');
-			return;
-		}
-		if(!confirm('Êtes-vous sûr de vouloir supprimer cet élément ?')) return;
-		$.action({
-			action : object.options.actions.element_delete,
-			path : object.selected.path,
-		},function(response){
-
-			object.triggerEvent('deleted',{
-				element : object.selected.element,
-				response : response,
-				path : object.selected.path,
-			});
 
-			object.selected.element.remove();
-			object.reset_preview();
-			object.remove_treeline(object.selected.element);
-		});
+		if(object.selected.length == 0) return $.message('info', 'Sélectionnez d\'abord un élément à supprimer');
+		if(!confirm('Êtes-vous sûr de vouloir supprimer '+(object.selected.length)+' élément ?')) return;
+
+		for(var k in object.selected){
+
+			var select = object.selected[k];
+
+			if($('span .rename-input:visible',select.element).length) continue;
+
+			$.action({
+				action : object.options.actions.element_delete,
+				path : select.path,
+			},function(response){
+
+				object.triggerEvent('deleted',{
+					element : select.element,
+					response : response,
+					path : select.path,
+				});
+
+				select.element.remove();
+				object.reset_preview();
+				object.remove_treeline(select.element);
+			});
+		}
 	}
 
 	DocumentApi.prototype.element_share_edit = function(){
 		var object = this;
-		if($('span .rename-input:visible',object.selected.element).length) return;
-		
-		if(object.selected == null) {
-			$.message('info', 'Sélectionnez d\'abord un élément à partager');
-			return;
-		}
+		if(object.selected.length==0) return $.message('info', 'Sélectionnez d\'abord un élément à partager');
+		var selected = object.selected[0];
 
+		if($('span .rename-input:visible',selected.element).length) return;
+		
 		$.action({
 			action : object.options.actions.element_share_edit,
-			path : object.selected.path,
+			path : selected.path,
 		});
 	}
 
@@ -1251,7 +1263,9 @@ var  DocumentApi = function(element,options) {
 				path : line.attr('data-path')
 		});
 
-		var ext = object.selected.path.split('.').pop();
+		var selected = object.selected[0];
+
+		var ext = selected.path.split('.').pop();
 		switch(ext){
 			case 'txt':
 			case 'html':
@@ -1269,7 +1283,7 @@ var  DocumentApi = function(element,options) {
 	// Téléchargement d'un élément de la GED
 	DocumentApi.prototype.element_download = function(line,forceDownload){
 		var object = this;
-		var line = line ? line : object.selected.element;
+		var line = line ? line : object.selected[0].element;
 		if(line.length == 0) return $.message('info', 'Sélectionnez d\'abord un élément à télécharger');
 			
 		object.triggerEvent('downloaded',{
@@ -1297,7 +1311,7 @@ var  DocumentApi = function(element,options) {
 		
 		$.action({
 			action : object.options.actions.properties_show,
-			id : object.selected.id
+			id : object.selected[0].id
 		},function(r){
 			$('.modal-body',modal).html(Mustache.render(tpl,r.row));
 			init_components(modal);
@@ -1320,11 +1334,11 @@ var  DocumentApi = function(element,options) {
 	DocumentApi.prototype.right_search = function(callback){
 		var object = this;
 	
-		if(object.selected == null) return;
+		if(object.selected.length == 0) return;
 
 		$('.element-rights').fill({
 			action:object.options.actions.right_search,
-			id : object.selected.id
+			id : object.selected[0].id
 		},function(){
 			if(callback!=null) callback();
 		});
@@ -1340,8 +1354,9 @@ var  DocumentApi = function(element,options) {
 			edit : $('.element-right-form input.edit').prop('checked') ? 1 :0,
 			recursive : $('.element-right-form input.recursive').prop('checked') ? 1 :0
 		}
+
 		data.action = object.options.actions.right_save;
-		data.element = object.selected.id;
+		data.element = object.selected[0].id;
 		$.action(data,function(r){
 			$.message('success','Enregistré');
 
@@ -1350,8 +1365,8 @@ var  DocumentApi = function(element,options) {
 			init_components('.element-right-form');
 			object.right_search();
 
-			data.id = object.selected.id;
-			data.element = object.selected.element;
+			data.id = object.selected[0].id;
+			data.element = object.selected[0].element;
 			object.triggerEvent('right-saved',data);
 
 

+ 3 - 3
plugin/dynamicform/DynamicField.class.php

@@ -121,8 +121,8 @@ class DynamicField extends Entity{
 			'label' => 'block', // inline (input group) / block (label classique) / none (pas de label)
 			'legend' => 'block', // block (span text muted) / none (pas de label)
 			'scope' => '', // ex : client
-			'uid' => '', // ex : 12 (Toxgen)
-			'firm' => $myFirm->id // ex : 1 (Sys1)
+			'uid' => '', // ex : 12 
+			'firm' => $myFirm->id // ex : 1 
 		),$params['options']);
 
 		$field['options'] = $options;
@@ -137,7 +137,7 @@ class DynamicField extends Entity{
 		$field['type'] = $field['type']->slug;
 
 
-		//On remplit les metas quoi qu'il en soit pour pouvoir récupérer toutes les valeurs d'un dictionnary / list
+		//On remplit les metas quoi qu'il en soit pour pouvoir récupérer toutes les valeurs d'un dictionary / list
 		if(isset($field['meta']) && !empty($field['meta'])){
 			$meta = json_decode(base64_decode($field['meta']),true);
 			if(is_array($meta)){

+ 9 - 8
plugin/dynamicform/DynamicForm.class.php

@@ -118,8 +118,8 @@ class DynamicForm extends Entity{
 			'input-class' => '', // classes additionnelles a placer sur les inputs
             'input-group-class' => '', // classes additionnelles a placer sur les groupes d'inputs
 			'scope' => '', // ex : client
-			'uid' => '', // ex : 12 (Toxgen)
-			'firm' => $myFirm->id // ex : 1 (Sys1)
+			'uid' => '', // ex : 12 
+			'firm' => $myFirm->id // ex : 1 
 		),$options);
 
 		$options['format'] = 'table';
@@ -146,8 +146,9 @@ class DynamicForm extends Entity{
 
 		$values = self::get_values($fieldsList,$options);
 
-		if(isset($options['arrayOutput']) && $options['arrayOutput'])
-			return self::get_values_as_array($values);
+		if(isset($options['arrayOutput']) && $options['arrayOutput']){
+			return self::get_values_as_array($fieldsList,$values);
+		}
 
 		//mise en page
 		foreach($fieldsTable as $i => $columns) {
@@ -191,7 +192,7 @@ class DynamicForm extends Entity{
 		global $myFirm;
 
 		$options = array_merge(array(
-			'firm' => $myFirm->id, // ex : 1 (Sys1)
+			'firm' => $myFirm->id, // ex : 1 
 			'format' => 'list' // table (mise en page ligne colonne) ou liste (a plat)
 		),$options);
 
@@ -328,9 +329,9 @@ class DynamicForm extends Entity{
 	 * @param <Array> tableau brut des valeurs des champs dynamiques
 	 * @return <Array> tableau des valeurs des champs dynamiques utilisables pour l'export
 	 */
-	public static function get_values_as_array($values){
+	public static function get_values_as_array($fields,$values){
 		$arrayOutput = array();
-		foreach($values as $field){
+		foreach($fields as $field){
 			$field['value']= isset($values[$field['id']]) ? $values[$field['id']] : '';
 			$arrayOutput[] = $field;
 		}
@@ -409,7 +410,7 @@ class DynamicForm extends Entity{
 
 		if(!isset($options['force-raw'])) $options['force-raw'] = false;
 
-		//Récupération des champs afin d'avoir les metas pour affichaqge fieldtypes exotique list, dictionnary...
+		//Récupération des champs afin d'avoir les metas pour affichaqge fieldtypes exotique list, dictionary...
 		$meta = array();
 		foreach(DynamicField::loadAll(array('slug:IN'=>array_keys($options['slugs']))) as $field)
 			$meta[$field->slug] = $field->meta;

+ 1 - 1
plugin/dynamicform/app.json

@@ -3,7 +3,7 @@
 	"name": "Formulaires dynamiques",
 	"author" : {
 		"name" : "Charles DUBOIS",
-		"mail" : "monmail@sys1.fr"
+		"mail" : "monmail@idleman.fr"
 	},
 	"version": "1.0",
 	"url": "http://no-url.com",

+ 2 - 2
plugin/dynamicform/dynamicform.plugin.php

@@ -60,10 +60,10 @@ function dynamic_types_filter($field,&$filterType,&$filterOptions){
 	        $filterType = $field['type']->slug;
 	        $filterOptions = ' data-filter-type="list" data-source="'.(isset($field['meta']) ? $field['meta'] : '').'" data-depth="1" data-disable-label ';
 	    break;
-	    case 'dictionnary':
+	    case 'dictionary':
 	        $filterType = $field['type']->slug;
 	        $meta = isset($field['meta']) ? json_decode(base64_decode($field['meta']), true) : array();
-	        $filterOptions = ' data-filter-type="dictionnary" data-slug="'.(isset($meta['slug']) ? $meta['slug'] : '').'" data-depth="1" data-disable-label ';
+	        $filterOptions = ' data-filter-type="dictionary" data-slug="'.(isset($meta['slug']) ? $meta['slug'] : '').'" data-depth="1" data-disable-label ';
 	    break;
 	    case 'checkbox-list':
 	        $filterType = $field['type']->slug;

+ 6 - 1
plugin/employee/Employee.class.php

@@ -19,6 +19,7 @@ class Employee extends Entity{
 	public $workplace; //Lieu de travail (Adresse)
 	public $hardware; //Mise a disposition de matériel (Liste configurable)
 	public $comment; //Comment (Wysiwyg)
+	public $state; //Etat (Texte)
 
 	
 	protected $TABLE_NAME = 'employee';
@@ -35,6 +36,7 @@ class Employee extends Entity{
 		'workplace' => array('type'=>'address', 'label' => 'Lieu de travail'),
 		'hardware' => array('type'=>'longstring', 'label' => 'Mise a disposition de matériel'),
 		'comment' => array('type'=>'wysiwyg', 'label' => 'Information sur le recrutement'),
+		'state' => array('type'=>'text', 'label' => 'Etat'),
 	);
 
 
@@ -115,7 +117,10 @@ class Employee extends Entity{
     	require_once(__DIR__.SLASH.'EmployeeWorkTime.class.php');
     	$contract = new EmployeeContract();
 
-    	$contracts = EmployeeContract::staticQuery('SELECT main.*,'.EmployeeWorkTime::joinString('wt').' FROM {{table}} main LEFT JOIN '.EmployeeWorkTime::tableName().' wt ON main.worktime = wt.id WHERE (main.`end` IS NULL OR main.`end` = "" OR  main.`end` > ?) AND main.employee=? LIMIT 1',array(time(),$this->id),true,1);
+    	$contracts = EmployeeContract::staticQuery('SELECT main.*,'.EmployeeWorkTime::joinString('wt').','.Dictionary::joinString('ty').' FROM {{table}} main 
+    		LEFT JOIN '.EmployeeWorkTime::tableName().' wt ON main.worktime = wt.id 
+    		LEFT JOIN '.Dictionary::tableName().' ty ON main.type = ty.id 
+    		WHERE (main.`end` IS NULL OR main.`end` = "" OR  main.`end` > ?) AND main.employee=? LIMIT 1',array(time(),$this->id),true,1);
 
     	if(isset($contracts[0])) $contract = $contracts[0];
 

+ 4 - 4
plugin/employee/EmployeeContract.class.php

@@ -1,7 +1,7 @@
 <?php
 /**
  * Define a Contrat employé
- * @author Sys1 ADMINISTRATEUR
+ * @author Kiss team
  * @category Plugin
  * @license copyright
  */
@@ -24,8 +24,8 @@ class EmployeeContract extends Entity{
 		'employee' => array('type'=>'integer','label' => 'Employé','link'=>'plugin/employee/Employee.class.php'),
 		'start' => array('type'=>'date','label' => 'Date de début'),
 		'end' => array('type'=>'date','label' => 'date de fin'),
-		'type' => array('type'=>'dictionnary','label' => 'Type de contrat'),
-		'statute' => array('type'=>'dictionnary','label' => 'Statut'),
+		'type' => array('type'=>'dictionary','label' => 'Type de contrat','link'=>'class/Dictionary.class.php'),
+		'statute' => array('type'=>'dictionary','label' => 'Statut'),
 		'salary' => array('type'=>'price','label' => 'Rémunération annuelle brute'),
 		'worktime' => array('type'=>'integer','label' => 'Temps de travail','link'=>'plugin/employee/EmployeeWorkTime.class.php'),
 		'comment' => array('type'=>'wysiwyg','label' => 'Commentaire')
@@ -35,4 +35,4 @@ class EmployeeContract extends Entity{
 	public $indexes = array();
 	
 }
-?>
+?>

+ 1 - 1
plugin/employee/EmployeeWorkTime.class.php

@@ -1,7 +1,7 @@
 <?php
 /**
  * Define a Temps de travail empoyé
- * @author Sys1 ADMINISTRATEUR
+ * @author Kiss team
  * @category Plugin
  * @license copyright
  */

+ 1 - 1
plugin/employee/action.php

@@ -49,7 +49,7 @@
 
 
 		//Recherche avancée
-		if(isset($_['filters']['advanced'])) filter_secure_query($_['filters']['advanced'],array('main.photo','main.birthName','main.name','main.firstname','main.job','main.jobDescription','main.manager','main.workplace','main.hardware','main.date'),$query,$data);
+		if(isset($_['filters']['advanced'])) filter_secure_query($_['filters']['advanced'],array('main.photo','main.birthName','main.name','main.firstname','main.job','main.jobDescription','man.account','main.workplace','main.hardware','main.date'),$query,$data);
 
 		//Tri des colonnes
 		if(isset($_['sort'])) sort_secure_query($_['sort'],array('main.birthName','main.name','main.firstname','main.job','main.jobDescription','main.manager','main.workplace','main.hardware','main.date'),$query,$data);

+ 5 - 3
plugin/employee/page.list.employee.php

@@ -33,8 +33,10 @@ require_once(__DIR__.SLASH.'Employee.class.php');
                 <option value="main.birthName" data-filter-type="text">Nom de naissance</option>
                 <option value="main.name" data-filter-type="text">Nom marital</option>
                 <option value="main.firstname" data-filter-type="text">Prénom</option>
-                <option value="main.job" data-filter-type="dictionnary">Poste</option>
-                <option value="main.manager" data-filter-type="user">Responsable</option>
+                <option value="main.job" data-filter-type="dictionary">Poste</option>
+                <?php if($myUser->can('employee','configure')): ?>
+                <option value="man.account" data-filter-type="user">Responsable</option>
+                <?php endif; ?>
                 <option value="main.workplace" data-filter-type="address">Lieu de travail</option>
             </select>
 
@@ -107,4 +109,4 @@ require_once(__DIR__.SLASH.'Employee.class.php');
           
     	</div>
     </div>
-</div>
+</div>

+ 1 - 1
plugin/employee/page.sheet.employee.php

@@ -13,7 +13,7 @@ if($employee->id == 0){
 	if(is_object($myEmployee)) $employee->manager = $myEmployee->id;
 }else{
 	if(!$myUser->can('employee','configure')){
-		$myEmployee = Employee::load(array('account'=>$myUser->login));
+		
 		if(!$myEmployee) throw new Exception('Vous n\'avez pas la permission de voir cette fiche');
 		if(!$myEmployee->can($employee,'read')) throw new Exception('Vous n\'avez pas la permission de voir cette fiche');
 	}

+ 1 - 1
plugin/example/ContactExample.class.php

@@ -47,7 +47,7 @@ class ContactExample extends Entity{
 		'manager' => array('type'=>'user', 'label' => 'Manager'),
 		'address' => array('type'=>'address', 'label' => 'Adresse'),
 		'properties' => array('type'=>'tag', 'label' => 'Tags'),
-		'vehicle' => array('type'=>'dictionnary', 'label' => 'Véhicule'),
+		'vehicle' => array('type'=>'dictionary', 'label' => 'Véhicule'),
 		'storyshort' => array('type'=>'textarea', 'label' => 'Histoire résumée'),
 		'story' => array('type'=>'wysiwyg', 'label' => 'Histoire riche'),
 		'password' => array('type'=>'password', 'label' => 'Mot de passe'),

+ 4 - 4
plugin/example/action.php

@@ -52,8 +52,8 @@
 
 		$contacts = ContactExample::staticQuery($query,$data,true,1);
 		
-		$vehicleList = Dictionnary::slugToArray('example_contact_vehicle',true);
-		$handicapList = Dictionnary::slugToArray('example_contact_handicap',true);
+		$vehicleList = Dictionary::slugToArray('example_contact_vehicle',true);
+		$handicapList = Dictionary::slugToArray('example_contact_handicap',true);
 
 		$response['rows'] = array();
 		//Mise en forme des résultats
@@ -67,12 +67,12 @@
 
 			$row['firm'] = $contact->join('firm')->toArray(); 
 			
-			$row['vehicle'] = isset($vehicleList[$row['vehicle']]) ? $vehicleList[$row['vehicle']] : new Dictionnary(); 
+			$row['vehicle'] = isset($vehicleList[$row['vehicle']]) ? $vehicleList[$row['vehicle']] : new Dictionary(); 
 			
 			$row['handicaps'] = array();
 			foreach(explode(',',$row['handicap']) as $id){
 				if(empty($id)) continue;
-				$row['handicaps'][] = isset($handicapList[$id]) ? $handicapList[$id] : new Dictionnary(); 
+				$row['handicaps'][] = isset($handicapList[$id]) ? $handicapList[$id] : new Dictionary(); 
 			}
 			
 			

+ 1 - 1
plugin/example/app.json

@@ -3,7 +3,7 @@
 	"name": "Example",
 	"author" : {
 		"name" : "Valentin CARRUESCO",
-		"mail" : "valentin.carruesco@sys1.fr"
+		"mail" : "contact@idleman.fr"
 	},
 	"version": "1.0",
 	"url": "http://no-url.com",

+ 29 - 35
plugin/example/example.plugin.php

@@ -32,13 +32,13 @@ function example_install($id){
 	if($id != 'fr.core.example') return;
 	Entity::install(__DIR__);
 
-	$dictionnary = new Dictionnary();
-    	$dictionnary->slug = 'example_contact_vehicle';
-    	if(Dictionnary::rowCount(array('slug'=>$dictionnary->slug)) ==0){
-	    	$dictionnary->label = 'ContactExample : Véhicule';
-	    	$dictionnary->parent = 0;
-	    	$dictionnary->state = Dictionnary::ACTIVE;
-	    	$dictionnary->save();
+	$dictionary = new Dictionary();
+    	$dictionary->slug = 'example_contact_vehicle';
+    	if(Dictionary::rowCount(array('slug'=>$dictionary->slug)) ==0){
+	    	$dictionary->label = 'ContactExample : Véhicule';
+	    	$dictionary->parent = 0;
+	    	$dictionary->state = Dictionary::ACTIVE;
+	    	$dictionary->save();
 
 	    	foreach(array(
 	    		'renaud'=>'Renaud',
@@ -46,46 +46,40 @@ function example_install($id){
 	    		'tesla'=>'Tesla'
 	    		
 	    	) as $key=>$value){
-		    	$item = new Dictionnary();
+		    	$item = new Dictionary();
 				$item->slug = 'example_contact_vehicle_'.$key;
 				$item->label = $value;
-				$item->parent = $dictionnary->id;
-				$item->state = Dictionnary::ACTIVE;
+				$item->parent = $dictionary->id;
+				$item->state = Dictionary::ACTIVE;
 				$item->save();
-
-
-				if($key == 'dacia'){
-					$subitem = new Dictionnary();
-				    $subitem->slug = 'example_contact_vehicle_dacia_logan';
-				    $subitem->label = 'Logan';
-				    $subitem->parent = $item->id;
-				    $subitem->state = Dictionnary::ACTIVE;
-				    $subitem->save();
-				}
-
 			}
 	    }
 
-	
+	$subitem = new Dictionary();
+    $subitem->slug = 'example_contact_vehicle_dacia_logan';
+    $subitem->label = 'Logan';
+    $subitem->parent = $item->id;
+    $subitem->state = Dictionary::ACTIVE;
+    $subitem->save();
     
-    $dictionnary = new Dictionnary();
-	$dictionnary->slug = 'example_contact_handicap';
-	if(Dictionnary::rowCount(array('slug'=>$dictionnary->slug)) ==0){
-    	$dictionnary->label = 'Example : Handicaps';
-    	$dictionnary->parent = 0;
-    	$dictionnary->state = Dictionnary::ACTIVE;
-    	$dictionnary->save();
+    $dictionary = new Dictionary();
+	$dictionary->slug = 'example_contact_handicap';
+	if(Dictionary::rowCount(array('slug'=>$dictionary->slug)) ==0){
+    	$dictionary->label = 'Example : Handicaps';
+    	$dictionary->parent = 0;
+    	$dictionary->state = Dictionary::ACTIVE;
+    	$dictionary->save();
 
     	foreach(array(
     		'none'=>'Aucun(e)',
     		'death'=>'Sourd(e)',
     		'blind'=>'Aveugle',
     	) as $key=>$value){
-	    	$item = new Dictionnary();
+	    	$item = new Dictionary();
 			$item->slug = 'example_contact_handicap_'.$key;
 			$item->label = $value;
-			$item->parent = $dictionnary->id;
-			$item->state = Dictionnary::ACTIVE;
+			$item->parent = $dictionary->id;
+			$item->state = Dictionary::ACTIVE;
 			$item->save();
 		}
     }
@@ -97,8 +91,8 @@ function example_uninstall($id){
 	if($id != 'fr.core.example') return;
 	Entity::uninstall(__DIR__);
 
-	Dictionnary::remove('example_contact_vehicle');
-	Dictionnary::remove('example_contact_handicap');
+	Dictionary::remove('example_contact_vehicle');
+	Dictionary::remove('example_contact_handicap');
     
 }
 
@@ -210,7 +204,7 @@ Configuration::setting('example',array(
     	"data-delete" => "contact_delete_document",
     	"documents" => json_encode(example_document_setting())
     )),
-    'example_dictionnary' => array("label"=>"Liste de véhicules","type"=>"dictionnary","legend"=>"la légende","attributes"=>array(
+    'example_dictionary' => array("label"=>"Liste de véhicules","type"=>"dictionary","legend"=>"la légende","attributes"=>array(
     	"data-slug" => "invoice-payment-mode"
     )),
 ));

+ 1 - 1
plugin/example/page.list.contact.php

@@ -100,7 +100,7 @@ if($myFirm->has_plugin('fr.core.dynamicform')){
                 <option value="main.address" data-filter-type="address">Adresse</option>
                 
                 <option value="main.properties" data-operator-delete='["in","not in"]' data-filter-type="tag">Tags</option>
-                <option value="main.vehicle" data-slug="example_contact_vehicle" data-depth="1" data-filter-type="dictionnary">Véhicule</option>
+                <option value="main.vehicle" data-slug="example_contact_vehicle" data-depth="1" data-filter-type="dictionary">Véhicule</option>
                 <option value="main.handicap" data-slug="example_contact_handicap"  data-filter-type="list" data-depth="3" data-multi-level-select="true">Handicaps</option>
                 <option value="main.solvability" data-filter-type="list"  data-values='<?php echo json_encode($solvabilities); ?>' >Solvabilité</option>
                 <option value="main.orientation"  data-filter-source='<?php echo json_encode($orientations); ?>' data-filter-type="choice">Orientation</option>

+ 7 - 7
plugin/example/page.sheet.contact.php

@@ -144,8 +144,8 @@ $data = array(
 * data-slug 			:	le slug de la liste mère à afficher
 * data-value 			:	la valeur de l'entité  à récup en base
 * data-output 			:	type de valeur de retour slug ou id de la liste (id par defaut)
-* data-disable-label 	:	cache le label de sous-liste si mentionné">(Select data-type="dictionnary")</small>
-			<select class="form-control select-control" type="text" data-type="dictionnary" data-slug="example_contact_vehicle" data-depth="2" key=data-disable-label data-value="<?php echo $contact->vehicle; ?>" id="vehicle" ></select>			
+* data-disable-label 	:	cache le label de sous-liste si mentionné">(Select data-type="dictionary")</small>
+			<select class="form-control select-control" type="text" data-type="dictionary" data-slug="example_contact_vehicle" data-depth="2" key=data-disable-label data-value="<?php echo $contact->vehicle; ?>" id="vehicle" ></select>			
 			<label for="storyshort">Histoire résumée</label>
 			<textarea  class="form-control" type="text" id="storyshort"><?php echo $contact->storyshort; ?></textarea>
 			<label for="story">Histoire riche</label>
@@ -199,7 +199,7 @@ $data = array(
 			<small class="text-muted" data-placement="right" data-tooltip title="* data-display			:	dropdown ou vide (vide=déplié)
 			* data-button			:	libellé/html du button si diaply en dropdown<br>
 			* data-values :valeurs possibles en json<br>
-			* data-slug : s'ajoute à data-values par les valeurs du dictionnary dont le slug est spécifié <br>
+			* data-slug : s'ajoute à data-values par les valeurs du dictionary dont le slug est spécifié <br>
 			* data-depth : spécifie la profondeur si un slug de distionnary est fournis <br>
 			"> (Input data-type="checkbox-list")</small><br>
 			<span class="text-warning">Mode plié, à choix multi niveau</span>
@@ -226,7 +226,7 @@ $data = array(
 			<label for="properties">Tags</label>
 			<small class="text-muted" data-placement="right" data-tooltip title="* data-multiple			:	Autorise l'utilisateur a sélectionner  des tag multiples
 			* data-autocomplete			:	Propose une autocompletion sur les mots clés
-			* data-dictionnary-slug : a spécifier si l'autocomplete est lié a un dictionnary">(Select data-type="tag")</small>
+			* data-dictionary-slug : a spécifier si l'autocomplete est lié a un dictionary">(Select data-type="tag")</small>
 			<input  value="<?php echo $contact->properties; ?>" class="form-control"  type="text"  data-type="tag"  data-multiple=true  id="properties" >
 			<label for="color">Couleur préférée</label>
 			<small class="text-muted"> (Input data-type="color")</small>
@@ -312,9 +312,9 @@ $data = array(
 			<?php endif; ?>
 		 	</div><br>
 
-		 	<label for="dictionnary-table">Tableau d'une liste</label>
-			<small class="text-muted"> (div data-type="dictionnary-table")</small>
-			<!-- <div data-type="dictionnary-table" data-dictionnary="example_contact_vehicle"></div> -->
+		 	<label for="dictionary-table">Tableau d'une liste</label>
+			<small class="text-muted"> (div data-type="dictionary-table")</small>
+			<!-- <div data-type="dictionary-table" data-dictionary="example_contact_vehicle"></div> -->
 			<br>
 
 			<?php if($myFirm->has_plugin('fr.core.stripe')) : ?>

+ 44 - 43
plugin/export/action.php

@@ -1,11 +1,10 @@
 <?php
-global $_,$conf;
-switch($_['action']){
+
 	/** TEMPLATE **/
 	
 	//Récuperation d'une liste de exportmodel
-	case 'export_model_search':
-		Action::write(function(&$response){
+	Action::register('export_model_search',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','read');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -84,11 +83,11 @@ switch($_['action']){
 					$response['rows'][] = $row;
 				}
 			}
-		});
-	break;
+		
+	});
+	
+	Action::register('export_model_format_refresh',function(&$response){
 	
-	case 'export_model_format_refresh':
-		Action::write(function(&$response){
 			global $myUser,$_;
 			User::check_access('export','edit');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -102,12 +101,12 @@ switch($_['action']){
 				default:
 				break;
 			}
-		});
-	break;
+		
+	});
 
 	//Ajout ou modification d'élément exportmodel
-	case 'export_model_save':
-		Action::write(function(&$response){
+	Action::register('export_model_save',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','edit');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -165,22 +164,22 @@ switch($_['action']){
 			$response['id'] = $item->id;
 
 			Log::put("Création/Modification d'export modèle ".$item->toText(), "Export Modèle");
-		});
-	break;
+		
+	});
 	
 	//Récuperation ou edition d'élément exportmodel
-	case 'export_model_edit':
-		Action::write(function(&$response){
+	Action::register('export_model_edit',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','edit');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
 			$response = ExportModel::getById($_['id']);
-		});
-	break;
+		
+	});
 
 	//Suppression d'élement exportmodel
-	case 'export_model_delete':
-		Action::write(function(&$response){
+	Action::register('export_model_delete',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','delete');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -199,12 +198,12 @@ switch($_['action']){
 			// $item->state = ExportModel::INACTIVE;
 			// $item->save();
 			Log::put("Suppression d'export modèle ".$item->toText(), "Export Modèle");
-		});
-	break;
+		
+	});
 
 	//Ajout document automatique à l'upload
-	case 'export_model_add_document':
-		Action::write(function(&$response){
+	Action::register('export_model_add_document',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','edit');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -240,12 +239,12 @@ switch($_['action']){
 
 			$response['ext'] = $ext;
 			$response['id'] = $exportmodel->id;
-		});
-	break;
+		
+	});
 
 	//Suppression document
-	case 'export_model_delete_document':
-		Action::write(function(&$response){
+	Action::register('export_model_delete_document',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','delete');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -260,21 +259,22 @@ switch($_['action']){
 			if(isset($matches[1])) ExportModel::change(array('export_format'=>NULL, 'filename'=>NULL), array('id'=>$matches[1]));
 
 			Log::put("Suppression de fichier modèle : ".$_['path'], "Export Modèle");
-		});
-	break;
+		
+	});
 
 	//Téléchargement des documents
-	case 'export_model_download_document':
+	Action::register('export_model_download_document',function(&$response){
 		global $myUser,$_;
 		User::check_access('export','read');
 		$path = (get_OS() === 'WIN') ? utf8_decode($_['path']) : $_['path'];
 		File::downloadFile(File::dir().'export'.SLASH.'documents'.SLASH.$path);
 
 		Log::put("Téléchargement du fichier modèle : ".$path, "Export Modèle");
-	break;
+		exit();
+	});
 
 	//Téléchargement des templates d'exemple
-	case 'export_model_download_template':
+	Action::register('export_model_download_template',function(&$response){
 		global $myUser,$_;
 		User::check_access('export','read');
 		if(!isset($_['extension']) || empty($_['extension'])) throw new Exception("Extension non précisée");
@@ -289,11 +289,12 @@ switch($_['action']){
 		File::downloadStream($stream, $_['filename'].'.'.$template['extension'],$template['mime']);
 
 		Log::put("Téléchargement d'un fichier modèle d'exemple : ".$_['filename'].'.'.$template['extension'], "Export Modèle");
-	break;
+		exit();
+	});
 
 	//Récupération du détail d'un jeu de donnée
-	case 'export_model_get_dataset':
-		Action::write(function(&$response){
+	Action::register('export_model_get_dataset',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','read');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -315,12 +316,12 @@ switch($_['action']){
 					'label'=> $set['label'].'.'.$template['extension']
 				);
 			}
-		});
-	break;
+		
+	});
 
 	//Choix du exportmodel pour export modèle
-	case 'export_model_export':
-		Action::write(function(&$response){
+	Action::register('export_model_export',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('export','read');
 			require_once(__DIR__.SLASH.'ExportModel.class.php');
@@ -388,7 +389,7 @@ switch($_['action']){
 					$fileInfo = file_put_contents($finalPath.$filename, $stream);
 				}
 			}
-		});
-	break;
-}
+		
+	});
+
 ?>

+ 2 - 5
plugin/export/export.plugin.php

@@ -29,10 +29,8 @@ function export_uninstall($id){
 Right::register('export',array('label'=>'Gestion des droits sur le plugin export'));
 
 
-//cette fonction comprends toutes les actions du plugin qui ne nécessitent pas de vue html
-function export_action(){
-	require_once(__DIR__.SLASH.'action.php');
-}
+//Comprends toutes les actions du plugin qui ne nécessitent pas de vue html
+require_once(__DIR__.SLASH.'action.php');
 
 //Déclaration du menu de réglages
 function export_menu_setting(&$settingMenu){
@@ -65,7 +63,6 @@ Plugin::addHook("uninstall", "export_uninstall");
 
 
 Plugin::addHook("page", "export_page");  
-Plugin::addHook("action", "export_action");  
 Plugin::addHook("menu_setting", "export_menu_setting");    
 Plugin::addHook("content_setting", "export_content_setting");
 ?>

+ 27 - 27
plugin/factory/action.php

@@ -1,9 +1,8 @@
 <?php
-global $_,$conf;
-switch($_['action']){
 
-	case 'factory_search_part':
-		Action::write(function(&$response){
+
+	Action::register('factory_search_part',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('factory','read');
 			require_once(__DIR__.SLASH.'Template.class.php');
@@ -16,20 +15,20 @@ switch($_['action']){
 				);
 				$i++; 
 			endforeach; 
-		});
-	break;
+		
+	});
 
-	case 'factory_search_filters':
-		Action::write(function(&$response){
+	Action::register('factory_search_filters',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('factory','read');
 			require_once(__DIR__.SLASH.'Template.class.php');
 			$response['rows'] = Template::filters($_['template']);
-		});
-	break;
+		
+	});
 
-	case 'factory_autocomplete_plugin':
-		Action::write(function(&$response){
+	Action::register('factory_autocomplete_plugin',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('factory','read');
 			$response['rows']  = array();
@@ -58,13 +57,13 @@ switch($_['action']){
 					$response['rows'][] = $manifest;
 				}
 			}
-		});
-	break;
+		
+	});
 
 
 
-	case 'factory_autocomplete_entity':
-		Action::write(function(&$response){
+	Action::register('factory_autocomplete_entity',function(&$response){
+	
 			global $myUser,$_;
 			$response['rows']  = array();
 
@@ -94,10 +93,10 @@ switch($_['action']){
 					'value'=> $entity
 				);
 			}
-		});
-	break;
-	case 'factory_autocomplete_entity_select':
-		Action::write(function(&$response){
+		
+	});
+	Action::register('factory_autocomplete_entity_select',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('factory','read');
 			$response['rows']  = array();
@@ -130,12 +129,12 @@ switch($_['action']){
 				$response['rows'][] = $type;
 			}
 	
-		});
-	break;
+		
+	});
 
-	case 'factory_render':
+	Action::register('factory_render',function(&$response){
 		User::check_access('factory','read');
-		global $myUser;
+		global $myUser,$_;
 		require_once(__DIR__.SLASH.'Template.class.php');
 
 		$entity = factory_sanitize($_['entity']);
@@ -200,7 +199,7 @@ switch($_['action']){
 						$value['values'] = array($value['key'].'-1'=>$value['label']);
 						
 					break;
-					case 'dictionnary':
+					case 'dictionary':
 						$value['attributes']['data-slug'] =	'"'.strtolower($plugin).'_'.strtolower($entity).'_'.$value['key'].'"';
 					break;
 					case 'int':
@@ -314,7 +313,8 @@ switch($_['action']){
 			file_put_contents($filePath,$stream);
 		}
 		echo htmlentities($stream);
-	break;
-}
+		exit();
+	});
+
 
 ?>

+ 4 - 7
plugin/factory/factory.plugin.php

@@ -41,10 +41,9 @@ function factory_uninstall($id){
 }
 
 
-//cette fonction comprends toutes les actions du plugin qui ne nécessitent pas de vue html
-function factory_action(){
-	require_once(__DIR__.SLASH.'action.php');
-}
+//Comprends toutes les actions du plugin qui ne nécessitent pas de vue html
+require_once(__DIR__.SLASH.'action.php');
+
 
 function factory_sanitize($text, $tableName=false,$allowChars='_'){
 	$returned = '';
@@ -78,8 +77,6 @@ Plugin::addHook("uninstall", "factory_uninstall");
 
 
 Plugin::addHook("menu_main", "factory_menu"); 
-Plugin::addHook("page", "factory_page");  
-Plugin::addHook("action", "factory_action");   
-
+Plugin::addHook("page", "factory_page");   
 
 ?>

+ 4 - 4
plugin/factory/template/Erp plugin/action.php

@@ -34,14 +34,14 @@
 		${{entity}}s = {{Entity}}::staticQuery($query,$data,true,{{linksCount}});{{/advanced-search}}
 		{{^advanced-search}}${{entity}}s = {{Entity}}::loadAll();{{/advanced-search}}
 
-		{{#fields}}{{#isDictionnary}}${{key}}List = Dictionnary::slugToArray('{{plugin}}_{{entity}}_{{key}}',true);{{/isDictionnary}}{{/fields}}
+		{{#fields}}{{#isDictionary}}${{key}}List = Dictionary::slugToArray('{{plugin}}_{{entity}}_{{key}}',true);{{/isDictionary}}{{/fields}}
 
 		$response['rows'] = array();
 		foreach(${{entity}}s as ${{entity}}){
 			$row = ${{entity}}->toArray();{{#links}}
 			$row['{{linkedKey}}'] = ${{entity}}->join('{{linkedKey}}')->toArray();{{/links}}{{#fields}}{{#isDate}}
-			$row['{{key}}-readable'] = complete_date($row['{{key}}']).' à '.date('H:i',$row['{{key}}']); {{/isDate}}{{#isDictionnary}}
-			$row['{{key}}'] = isset(${{key}}List[$row['{{key}}']]) ? ${{key}}List[$row['{{key}}']] : new Dictionnary(); {{/isDictionnary}}{{#isList}}
+			$row['{{key}}-readable'] = complete_date($row['{{key}}']).' à '.date('H:i',$row['{{key}}']); {{/isDate}}{{#isDictionary}}
+			$row['{{key}}'] = isset(${{key}}List[$row['{{key}}']]) ? ${{key}}List[$row['{{key}}']] : new Dictionary(); {{/isDictionary}}{{#isList}}
 			$row['{{key}}'] = {{Entity}}::{{key}}s($row['{{key}}']); {{/isList}}{{#isChoice}}
 			$row['{{key}}'] = {{Entity}}::{{key}}s($row['{{key}}']); {{/isChoice}}{{#isWysiwyg}}
 			$row['{{key}}'] = html_entity_decode($row['{{key}}']); {{/isWysiwyg}}{{#isUser}}
@@ -91,7 +91,7 @@
 		require_once(__DIR__.SLASH.'{{Entity}}.class.php');
 		$item = {{Entity}}::provide();{{#history-save}}
 		$oldItem = clone $item;{{/history-save}}{{#fields}}{{^isFile}}{{^isImage}}
-		{{#isFloat}}if(is_numeric($_['{{key}}'])) {{/isFloat}}{{#isDictionnary}}if(!empty($_['{{key}}']) && is_numeric($_['{{key}}'])) {{/isDictionnary}}{{#isChoice}}if(!empty($_['{{key}}']))  {{/isChoice}}$item->{{key}} = {{#isDate}}timestamp_date($_['{{key}}']);{{/isDate}}{{^isDate}}$_['{{key}}'];{{/isDate}}{{/isImage}}{{/isFile}}{{/fields}}
+		{{#isFloat}}if(is_numeric($_['{{key}}'])) {{/isFloat}}{{#isDictionary}}if(!empty($_['{{key}}']) && is_numeric($_['{{key}}'])) {{/isDictionary}}{{#isChoice}}if(!empty($_['{{key}}']))  {{/isChoice}}$item->{{key}} = {{#isDate}}timestamp_date($_['{{key}}']);{{/isDate}}{{^isDate}}$_['{{key}}'];{{/isDate}}{{/isImage}}{{/isFile}}{{/fields}}
 		$item->save();{{#fields}}{{#isImage}}
 		//Ajout upload {{label}}
 		if(!empty($_['{{key}}']))

+ 2 - 2
plugin/factory/template/Erp plugin/page.list.{{entity.readable}}.php

@@ -58,7 +58,7 @@ foreach ({{Entity}}::{{key}}s() as $key => ${{key}}) {
                                 [-[-#{{key}}-]-]
                                 <li class="list-group-item p-1"><a href="[-[-url-]-]">[-[-label-]-]</a></li>
                                 [-[-/{{key}}-]-]
-                            </ul>{{/isFile}}{{#isImage}}<img class="shadow-sm rounded-sm" style="max-width: 100px;height: auto;" src="[-[-{{key}}-]-]">{{/isImage}}{{#isUrl}}<a href="[-[-{{key}}-]-]">[-[-{{key}}-]-]</a>{{/isUrl}}{{#isUser}}<img src="[-[-{{key}}.avatar-]-]" class="avatar-mini avatar-rounded avatar-login" title="[-[-{{key}}.fullName-]-]"> [-[-{{key}}.fullName-]-]{{/isUser}}{{#isColor}}<i class="fas fa-dot-circle" style="color:[-[-{{key}}-]-]"></i> {{/isColor}}{{#isBoolean}}[-[-#{{key}}-]-] <i class="fas fa-check text-success"></i> OUI[-[-/{{key}}-]-][-[-^{{key}}-]-]<i class="fas fa-times text-danger"></i> Non[-[-/{{key}}-]-]{{/isBoolean}}{{#isIcon}}<i class="[-[-{{key}}-]-]"></i> {{/isIcon}}{{#isWysiwyg}}{[-[-{{key}}-]-]}{{/isWysiwyg}}{{#isDate}}[-[-{{key}}-readable-]-]{{/isDate}}{{#isList}}[-[-{{key}}.label-]-]{{/isList}}{{#isDictionnary}}[-[-{{key}}.label-]-]{{/isDictionnary}}{{#isChoice}}[-[-{{key}}.label-]-]{{/isChoice}}{{^isUrl}}{{^isFile}}{{^isImage}}{{^isUser}}{{^isBoolean}}{{^isWysiwyg}}{{^isDate}}{{^isDictionnary}}{{^isList}}{{^isChoice}}[-[-{{key}}-]-]{{/isChoice}}{{/isList}}{{/isDictionnary}}{{/isDate}}{{/isWysiwyg}}{{/isBoolean}}{{/isUser}}{{/isImage}}{{/isFile}}{{/isUrl}}</div>{{/fields}}
+                            </ul>{{/isFile}}{{#isImage}}<img class="shadow-sm rounded-sm" style="max-width: 100px;height: auto;" src="[-[-{{key}}-]-]">{{/isImage}}{{#isUrl}}<a href="[-[-{{key}}-]-]">[-[-{{key}}-]-]</a>{{/isUrl}}{{#isUser}}<img src="[-[-{{key}}.avatar-]-]" class="avatar-mini avatar-rounded avatar-login" title="[-[-{{key}}.fullName-]-]"> [-[-{{key}}.fullName-]-]{{/isUser}}{{#isColor}}<i class="fas fa-dot-circle" style="color:[-[-{{key}}-]-]"></i> {{/isColor}}{{#isBoolean}}[-[-#{{key}}-]-] <i class="fas fa-check text-success"></i> OUI[-[-/{{key}}-]-][-[-^{{key}}-]-]<i class="fas fa-times text-danger"></i> Non[-[-/{{key}}-]-]{{/isBoolean}}{{#isIcon}}<i class="[-[-{{key}}-]-]"></i> {{/isIcon}}{{#isWysiwyg}}{[-[-{{key}}-]-]}{{/isWysiwyg}}{{#isDate}}[-[-{{key}}-readable-]-]{{/isDate}}{{#isList}}[-[-{{key}}.label-]-]{{/isList}}{{#isDictionary}}[-[-{{key}}.label-]-]{{/isDictionary}}{{#isChoice}}[-[-{{key}}.label-]-]{{/isChoice}}{{^isUrl}}{{^isFile}}{{^isImage}}{{^isUser}}{{^isBoolean}}{{^isWysiwyg}}{{^isDate}}{{^isDictionary}}{{^isList}}{{^isChoice}}[-[-{{key}}-]-]{{/isChoice}}{{/isList}}{{/isDictionary}}{{/isDate}}{{/isWysiwyg}}{{/isBoolean}}{{/isUser}}{{/isImage}}{{/isFile}}{{/isUrl}}</div>{{/fields}}
                     <div class="align-middle text-right">
                         <div class="btn-group btn-group-sm" role="group">
                             {{^edit-form}}<a class="btn text-info" title="Éditer {{entity_readable}}" href="index.php?module={{plugin}}&page=sheet.{{entity.readable}}&id=[-[-id-]-]"><i class="fas fa-pencil-alt"></i></a>{{/edit-form}}
@@ -97,7 +97,7 @@ foreach ({{Entity}}::{{key}}s() as $key => ${{key}}) {
                                 [-[-#{{key}}-]-]
                                 <li class="list-group-item p-1"><a href="[-[-url-]-]">[-[-label-]-]</a></li>
                                 [-[-/{{key}}-]-]
-                            </ul>{{/isFile}}{{#isImage}}<img class="shadow-sm rounded-sm" style="max-width: 100px;height: auto;" src="[-[-{{key}}-]-]">{{/isImage}}{{#isUrl}}<a href="[-[-{{key}}-]-]">[-[-{{key}}-]-]</a>{{/isUrl}}{{#isUser}}<img src="[-[-{{key}}.avatar-]-]" class="avatar-mini avatar-rounded avatar-login" title="[-[-{{key}}.fullName-]-]"> [-[-{{key}}.fullName-]-]{{/isUser}}{{#isColor}}<i class="fas fa-dot-circle" style="color:[-[-{{key}}-]-]"></i> {{/isColor}}{{#isBoolean}}[-[-#{{key}}-]-] <i class="fas fa-check text-success"></i> OUI[-[-/{{key}}-]-][-[-^{{key}}-]-]<i class="fas fa-times text-danger"></i> Non[-[-/{{key}}-]-]{{/isBoolean}}{{#isIcon}}<i class="[-[-{{key}}-]-]"></i> {{/isIcon}}{{#isWysiwyg}}{[-[-{{key}}-]-]}{{/isWysiwyg}}{{#isDate}}[-[-{{key}}-readable-]-]{{/isDate}}{{#isList}}[-[-{{key}}.label-]-]{{/isList}}{{#isDictionnary}}[-[-{{key}}.label-]-]{{/isDictionnary}}{{#isChoice}}[-[-{{key}}.label-]-]{{/isChoice}}{{^isUrl}}{{^isFile}}{{^isImage}}{{^isUser}}{{^isBoolean}}{{^isWysiwyg}}{{^isDate}}{{^isDictionnary}}{{^isList}}{{^isChoice}}[-[-{{key}}-]-]{{/isChoice}}{{/isList}}{{/isDictionnary}}{{/isDate}}{{/isWysiwyg}}{{/isBoolean}}{{/isUser}}{{/isImage}}{{/isFile}}{{/isUrl}}</td>{{/fields}}
+                            </ul>{{/isFile}}{{#isImage}}<img class="shadow-sm rounded-sm" style="max-width: 100px;height: auto;" src="[-[-{{key}}-]-]">{{/isImage}}{{#isUrl}}<a href="[-[-{{key}}-]-]">[-[-{{key}}-]-]</a>{{/isUrl}}{{#isUser}}<img src="[-[-{{key}}.avatar-]-]" class="avatar-mini avatar-rounded avatar-login" title="[-[-{{key}}.fullName-]-]"> [-[-{{key}}.fullName-]-]{{/isUser}}{{#isColor}}<i class="fas fa-dot-circle" style="color:[-[-{{key}}-]-]"></i> {{/isColor}}{{#isBoolean}}[-[-#{{key}}-]-] <i class="fas fa-check text-success"></i> OUI[-[-/{{key}}-]-][-[-^{{key}}-]-]<i class="fas fa-times text-danger"></i> Non[-[-/{{key}}-]-]{{/isBoolean}}{{#isIcon}}<i class="[-[-{{key}}-]-]"></i> {{/isIcon}}{{#isWysiwyg}}{[-[-{{key}}-]-]}{{/isWysiwyg}}{{#isDate}}[-[-{{key}}-readable-]-]{{/isDate}}{{#isList}}[-[-{{key}}.label-]-]{{/isList}}{{#isDictionary}}[-[-{{key}}.label-]-]{{/isDictionary}}{{#isChoice}}[-[-{{key}}.label-]-]{{/isChoice}}{{^isUrl}}{{^isFile}}{{^isImage}}{{^isUser}}{{^isBoolean}}{{^isWysiwyg}}{{^isDate}}{{^isDictionary}}{{^isList}}{{^isChoice}}[-[-{{key}}-]-]{{/isChoice}}{{/isList}}{{/isDictionary}}{{/isDate}}{{/isWysiwyg}}{{/isBoolean}}{{/isUser}}{{/isImage}}{{/isFile}}{{/isUrl}}</td>{{/fields}}
     	                <td class="align-middle text-right">
                             <div class="btn-group btn-group-sm" role="group">
                                 {{^edit-form}}<a class="btn text-info" title="Éditer {{entity_readable}}" href="index.php?module={{plugin}}&page=sheet.{{entity.readable}}&id=[-[-id-]-]"><i class="fas fa-pencil-alt"></i></a>{{/edit-form}}

+ 16 - 16
plugin/factory/template/Erp plugin/{{plugin}}.plugin.php

@@ -33,38 +33,38 @@ function {{plugin}}_install($id){
 	if($id != 'fr.core.{{plugin}}') return;
 	Entity::install(__DIR__);
 
-	{{#fields}}{{#isDictionnary}}$dictionnary = new Dictionnary();
-    	$dictionnary->slug = '{{plugin}}_{{entity}}_{{key}}';
-    	if(Dictionnary::rowCount(array('slug'=>$dictionnary->slug)) ==0){
-	    	$dictionnary->label = '{{EntityLabel}} : {{label}}';
-	    	$dictionnary->parent = 0;
-	    	$dictionnary->state = Dictionnary::ACTIVE;
-	    	$dictionnary->save();
+	{{#fields}}{{#isDictionary}}$dictionary = new Dictionary();
+    	$dictionary->slug = '{{plugin}}_{{entity}}_{{key}}';
+    	if(Dictionary::rowCount(array('slug'=>$dictionary->slug)) ==0){
+	    	$dictionary->label = '{{EntityLabel}} : {{label}}';
+	    	$dictionary->parent = 0;
+	    	$dictionary->state = Dictionary::ACTIVE;
+	    	$dictionary->save();
 
 	    	foreach(array(
 	    		'none'=>'Aucun(e)',
 	    	) as $key=>$value){
-		    	$item = new Dictionnary();
+		    	$item = new Dictionary();
 				$item->slug = '{{plugin}}_{{entity}}_{{key}}_'.$key;
 				$item->label = $value;
-				$item->parent = $dictionnary->id;
-				$item->state = Dictionnary::ACTIVE;
+				$item->parent = $dictionary->id;
+				$item->state = Dictionary::ACTIVE;
 				$item->save();
 			}
 	    }
-    {{/isDictionnary}}{{/fields}}
+    {{/isDictionary}}{{/fields}}
 }
 
 //Fonction executée lors de la désactivation du plugin
 function {{plugin}}_uninstall($id){
 	if($id != 'fr.core.{{plugin}}') return;
 	Entity::uninstall(__DIR__);
-	{{#fields}}{{#isDictionnary}}$dictionnary = Dictionnary::bySlug('{{plugin}}_{{entity}}_{{key}}');
-    	if($dictionnary!= false && $dictionnary->id!=0){
-    		Dictionnary::delete(array('parent'=>$dictionnary->id));
-    		Dictionnary::delete(array('id'=>$dictionnary->id));
+	{{#fields}}{{#isDictionary}}$dictionary = Dictionary::bySlug('{{plugin}}_{{entity}}_{{key}}');
+    	if($dictionary!= false && $dictionary->id!=0){
+    		Dictionary::delete(array('parent'=>$dictionary->id));
+    		Dictionary::delete(array('id'=>$dictionary->id));
     	}
-    {{/isDictionnary}}{{/fields}}
+    {{/isDictionary}}{{/fields}}
 }
 
 //Déclaration des sections de droits du plugin

+ 0 - 30
plugin/factory/template/Test template/list.php

@@ -1,30 +0,0 @@
-{"label":"Liste entité","syntax":"php","options": {"edit-form":"edit-form"}}
-<?php
-global $myUser;
-User::check_access('{{plugin}}','read');
-require_once(__DIR__.SLASH.'{{Entity}}.class.php');
-?>
-
-
-Boucle 
-{{#fields}}
-   - {{entity}}.{{key}} {{type.label}} on {{plugin}} {{/fields}}
-
-IF Boucle  
-<ul>
-{{#fields}}
-   <li>
-    {{entity}}.{{key}} :  {{#edit-form}} OUI {{/edit-form}}  {{^edit-form}} NON {{/edit-form}}
-   </li> {{/fields}}
-</ul>
-
-
-Boucle dans IF
-
-{{#edit-form}}
-<ul>
-    {{#fields}}
-    {{key}}
-    {{/fields}}
-</ul>
-{{/edit-form}}

+ 0 - 22
plugin/factory/template/Wordpress plugin/action.php

@@ -1,22 +0,0 @@
-{"label":"Action","syntax":"php"}
-<?php 
-$_ = array_merge($_POST,$_GET);
-
-if(isset($_['custom_action'])){
-	$response = array();
-	switch($_['custom_action']):
-		case '{{plugin}}_{{entity}}_save':
-
-		break;
-		case '{{plugin}}_{{entity}}_search':
-
-		break;
-	endswitch;
-
-	if(isset($response) && is_array($response)){
-		header('Content-type: application/json');
-		echo json_encode($response);
-	}
-	exit();
-}
-?>

+ 0 - 1
plugin/factory/template/Wordpress plugin/css/main.css

@@ -1 +0,0 @@
-{"label":"CSS","syntax":"css"}

+ 0 - 6
plugin/factory/template/Wordpress plugin/functions.php

@@ -1,6 +0,0 @@
-{"label":"Fonctions","syntax":"php"}
-<?php 
-
-
-
-?>

+ 0 - 51
plugin/factory/template/Wordpress plugin/js/main.js

@@ -1,51 +0,0 @@
-{"label":"JS","syntax":"js"}
-
-
-jQuery(document).ready(function($) {
-   
-});
-
-/* {{ENTITY}} **/
-
-// Search
-function {{plugin}}_{{entity}}_search() {
-	
-	var data = {
-		custom_action: '{{plugin}}_{{entity}}_search',
-	};
-
-	$.ajax({
-		url : document.URL,
-		method : 'POST',
-		data: data,
-		success : function(r){
-			
-		},
-		error: function(xhr, status, error) {
-			
-		}
-	});
-}
-
-
-// Save
-function {{plugin}}_{{entity}}_save(){
-	
-	var data = {};
-
-	data.custom_action =  '{{plugin}}_{{entity}}_save';
-
-	$.ajax({
-		url : document.URL,
-		method : 'POST',
-		data: data,
-		success : function(r){
-			
-		},
-		error : function(xhr, status, error) {
-			
-		}
-	});
-}
-
-

+ 0 - 254
plugin/factory/template/Wordpress plugin/sys1.{{plugin}}.php

@@ -1,254 +0,0 @@
-{"label":"Plugin","syntax":"php"}
-<?php
-/**
- * Plugin Name:  {{plugin}}
- * Plugin URI: http://no-url.com
- * Description: {{description}}
- * Version: 1.0.0
- * Author: {{user.fullname}}
- * Author URI: https://sys1.fr
- * License: Copyright 
- */
-
-function sys1_{{plugin}}_init() 
-	//Permet de créer un type de posts personnalisé, avec un menu dédié
-	$labels = array(
-		'name'                => _x( '{{Entity}}s', 'Post Type General Name'),
-		'singular_name'       => _x( '{{Entity}}', 'Post Type Singular Name'),
-		'menu_name'           => __( '{{Entity}}s'),
-		'all_items'           => __( 'Toutes les {{entity}}s'),
-		'view_item'           => __( 'Voir l\'{{entity}}'),
-		'add_new_item'        => __( 'Ajouter une nouvelle {{entity}}'),
-		'add_new'             => __( 'Ajouter'),
-		'edit_item'           => __( 'Editer l\'{{entity}}'),
-		'update_item'         => __( 'Modifier l\'{{entity}}'),
-		'search_items'        => __( 'Rechercher une {{entity}}'),
-		'not_found'           => __( 'Non trouvée'),
-		'not_found_in_trash'  => __( 'Non trouvée dans la corbeille'),
-	);
-	$args = array(
-		'label'               => __( '{{Entity}}s'),
-		'description'         => __( '{{description}}'),
-		'labels'              => $labels,
-		'supports'            => array( 'title', 'thumbnail'),
-		'menu_icon'           => 'dashicons-admin-multisite',
-		'hierarchical'        => false,
-		'public'              => true,
-		'has_archive'         => false,
-		'rewrite'			  => array( 'slug' => '{{entity}}s'),
-	);
-	register_post_type( '{{entity}}s', $args );
-
-	//Inclus le fichier action.php
-	require_once(__DIR__.DIRECTORY_SEPARATOR.'functions.php');
-	add_rewrite_endpoint( 'action.php', EP_ROOT );
-}
-
-
-
-//Permet de gérer l'affichage du conteneur des champs personnalisés dans l'interface de création d'une nouvelle {{entity}}
-function show_{{entity}}_meta_box() {
-	global $post;  
-	$meta = get_post_meta( $post->ID, '{{entity}}_fields', true ); 
-
-
-	require_once(__DIR__.DIRECTORY_SEPARATOR.'{{Entity}}.class.php');
-	${{entity}} = new {{Entity}}();
-	${{entity}}->fromArray($meta);
-	?>
-	<input type="hidden" name="{{entity}}_meta_box_nonce" value="<?php echo wp_create_nonce( basename(__FILE__) ); ?>">
-	<table id="fieldsSettings">
-		{{:fields}}<tr>
-			<td><label for="{{value.key}}">{{value.label}}</label></td>
-			<td>
-				<!-- TODO !! : remplacer name="{{value.key}}" par name="{{entity}}_fields[{{value.key}}]" -->
-				{{value.input}}
-			</td>
-		</tr>{{/:fields}}
-	</table>
-	<?php 
-}
-
-
-//Permet de sauvegarder les différents champs personnalisés créés avec le custom post type
-//
-function save_{{entity}}_fields_meta($post_id) {
-	if (wp_is_post_revision($post_id))
-		return;
-
-	// Check du nonce
-	if (!wp_verify_nonce($_POST['{{entity}}_meta_box_nonce'], basename(__FILE__))) return $post_id; 
-	// Check de l'autosave
-	if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return $post_id;
-	
-	// Check des permissions
-	if ('page' === $_POST['post_type']) {
-		if ( !current_user_can('edit_page', $post_id) || !current_user_can('edit_post', $post_id)) 
-			return $post_id;
-	}
-	
-	$old = get_post_meta($post_id, '{{entity}}_fields', true);
-	$new = $_POST['{{entity}}_fields'];
-
-	if ($new && $new !== $old) {
-		update_post_meta($post_id, '{{entity}}_fields', $new);
-	} elseif ('' === $new && $old) {
-		delete_post_meta($post_id, '{{entity}}_fields', $old);
-	}
-}
-
-
-//Permet d'afficher l'intégralité du contenu du formulaire de soumission d'une {{entity}}
-function sys1_{{plugin}}_shortcode($attributes) {
-	
-	ob_start();
-?>
-	<div id="{{plugin}}-submit-form">
-		<input type="hidden" name="{{plugin}}_meta_box_nonce" id="{{plugin}}_meta_box_nonce" value="<?php echo wp_create_nonce( '{{plugin}}' ); ?>">
-		{{:fields}}<div>
-			<label for="post_title"><span>{{value.label}} *</span></label>
-			{{value.input}}
-		</div>{{/:fields}}
-		<div class="g-recaptcha" id="captcha" data-sitekey=" <?php echo get_option( 'recaptcha_public_{{plugin}}' ) ?>"></div>
-		<div class="generalButton" id="submitButton" onclick="sys1_{{plugin}}_save();"><div class="hoverButton">Soumettre</div></div>
-	</div>
-
-<?php
-	$output = ob_get_clean();
-	return $output;
-}
-
-
-
-// Ajout du sous-menu "Paramètres" dans l'onglet {{Plugin}}, afin de gérer les différents élémentsutiles au plugin (captcha keys, email, shortcode)
-function sys1_{{plugin}}_settings() {
-	add_submenu_page(
-		'edit.php?post_type={{entity}}s',
-		__('Paramètres - Plugin SYS1 {{Plugin}}s','menu-test'),
-		__('Paramètres','menu-test'),
-		'manage_options',
-		'sys1_{{plugin}}_settings',
-		'show_{{plugin}}_settings_page'
-	);
-}
-
-
-
-//Ajout des champs de configuration du plugin SYS1 {{Entity}} sur l'onglet de menu {{plugin}}cié
-function sys1_{{plugin}}_admin(){
-
-	add_meta_box(
-		// id
-		'{{entity}}_meta_box', 		
-		// titre	
-		'Informations : {{entity}}',   
-		//Callback
-		'show_{{entity}}_meta_box', 
-		//Screen		
-		'{{entity}}s', 	
-		//Contexte				
-		'normal',
-		//Priorité							
-		'high' 								
-	);
-
-	$customsSettings = array(
-		"recaptcha_url_{{plugin}}" => array(
-			"title" 	  => "Recaptcha url",
-			"placeholder" => "https://www.google.com/recaptcha/api/siteverify"
-		),
-		"recaptcha_public_{{plugin}}" => array(
-			"title" 	  => "Recaptcha clé publique",
-			"placeholder" => "ex: 6LeuNQITAAAAAPGRU7dkrCPIrrR64WPvzMc7pn6Z"
-		),
-		"recaptcha_secret_{{plugin}}" =>  array(
-			"title" 	  => "Recaptcha clé privée",
-			"placeholder" => "ex: 6LeuNQITAAAAAHwUcbXbyFCUudJKRAjcgNRwlaoE"
-		),
-		"api_key_gmaps_geocode" =>  array(
-			"title" 	  => "Geocode clé privée",
-			"placeholder" => ""
-		),
-		"notification_email_{{plugin}}" => array(
-			"title" 	  => "Email notification d'inscription d'{{entity}}",
-			"placeholder" => "votre.email@example.fr"
-		)
-	);
-
-	add_settings_section(
-		'sys1_{{plugin}}_settings_section', 
-		'Option plugin {{Entity}}s', 
-		function(){
-			echo '<p>Paramétrage du plugin {{plugin}}</p>'; 
-		},
-		'sys1_{{plugin}}_settings'
-	);
-
-
-	foreach($customsSettings as $slug => $values){
-		add_settings_field(
-			$slug,
-			$values['title'], 
-			function($args){
-				$option = get_option($args[0]);
-				echo '<input type="text" id="'. $args[0] .'" name="'. $args[0] .'" value="' . $option . '" class="regular-text ltr" placeholder="'.$values['placeholder'].'" />';
-			}, 
-			'sys1_{{plugin}}_settings', 
-			'sys1_{{plugin}}_settings_section', 
-			array($slug)  
-		);
-		register_setting('sys1_{{plugin}}_settings_group',$slug, 'esc_attr');
-	}
-}
-
-
-//Gestion de l'affichage de la page des paramètres du plugin des {{Entity}}s.
-function show_{{plugin}}_settings_page() {
-?>
-	<div class='wrap'>
-		<h2>Paramètres</h2>
-		<hr>
-		<div id="shortcodeContainer">
-			<ul>
-				<li>Afin d'afficher le plugin {{plugin}} sur une page, utilisez le shortcode suivant : <strong>[sys1_{{plugin}}]</strong></li>
-			</ul>
-		</div>
-		<hr>
-		<form method='post' action='options.php'>
-			<?php 
-			settings_fields( 'sys1_{{plugin}}_settings_group' );
-			do_settings_sections( 'sys1_{{plugin}}_settings' );
-			?>
-			<p class='submit'>
-				<input name='submit' type='submit' id='submit' class='button-primary' value='<?php _e("Save Changes") ?>' />
-			</p>
-		</form>
-	</div>
-<?php
-}
-
-
-// Ajout de la variable action.php pour que Wordpress le trouve et ne l'ignore pas
-function {{plugin}}_add_query_vars($vars){
-	$vars[] = "action.php";
-	return $vars;
-}
-
-function action_{{plugin}}_parsing(){
-	require_once(__DIR__.DIRECTORY_SEPARATOR.'action.php');
-}
-
-//Création des différents hooks
-wp_enqueue_script('sys1_{{plugin}}_js', plugin_dir_url(__FILE__) . '/js/main.js?v=1', array('jquery'));
-wp_enqueue_style('sys1_{{plugin}}_css', plugin_dir_url(__FILE__) . '/css/main.css?v=1');
-
-
-add_action('admin_init', 'sys1_{{plugin}}_admin', 200);
-add_action('admin_menu', 'sys1_{{plugin}}_settings');
-add_action('save_post', 'save_{{entity}}_fields_meta', 10);
-
-
-add_action('init', 'sys1_{{plugin}}_init');
-add_action('parse_request','action_{{plugin}}_parsing');
-add_shortcode('sys1_{{plugin}}', 'sys1_{{plugin}}_shortcode', 10);
-add_filter( 'query_vars', '{{plugin}}_add_query_vars');

+ 0 - 18
plugin/factory/template/Wordpress plugin/{{Entity}}.class.php

@@ -1,18 +0,0 @@
-{"label":"Classe","syntax":"php"}
-<?php
-/**
- * Define a {{entity}}.
- * @author {{user.fullname}}
- * @category Plugin
- * @license copyright
- */
-class {{Entity}} {
-	public $id{{:fields}},${{value.key}}{{/:fields}};
-	
-	function fromArray($array = array()){
-		foreach ($array as $key => $value) {
-			$this->$key = $value;
-		}
-	}
-}
-?>

+ 1 - 1
plugin/glpi/Glpi.class.php

@@ -85,7 +85,7 @@ class GLPI{
 			foreach ($response['data'] as $ticket) {
 				$tickets[] = array(
 					'id' => $ticket[2],
-					'url' => 'https://glpi.sys1.fr/front/ticket.form.php?id='.$ticket[2],
+					'url' => 'https://glpi.kiss.fr/front/ticket.form.php?id='.$ticket[2],
 					'subject' => $ticket[1],
 					'date' => $ticket[15],
 					'firm' => $ticket[80],

+ 23 - 31
plugin/glpi/action.php

@@ -1,30 +1,25 @@
 <?php
-global $_,$conf;
-switch($_['action']){
 
-	
 	//Sauvegarde des configurations de glpi
-	case 'glpi_setting_save':
-		Action::write(function(&$response){
-			global $myUser,$_,$conf;
-			User::check_access('glpi','configure');
+	Action::register('glpi_setting_save',function(&$response){
+		global $myUser,$_,$conf;
+		User::check_access('glpi','configure');
 
-			//Si input file "multiple", possibilité de normlaiser le
-			//tableau $_FILES récupéré avec la fonction => normalize_php_files();
-			
-			foreach(Configuration::setting('glpi') as $key=>$value){
-				if(!is_array($value)) continue;
-				$allowed[] = $key;
-			}
-			foreach ($_['fields'] as $key => $value) {
-				if(in_array($key, $allowed))
-					$conf->put($key,$value);
-			}
-		});
-	break;
+		//Si input file "multiple", possibilité de normlaiser le
+		//tableau $_FILES récupéré avec la fonction => normalize_php_files();
+		
+		foreach(Configuration::setting('glpi') as $key=>$value){
+			if(!is_array($value)) continue;
+			$allowed[] = $key;
+		}
+		foreach ($_['fields'] as $key => $value) {
+			if(in_array($key, $allowed))
+				$conf->put($key,$value);
+		}
+	});
 	
 
-	case 'glpi_widget_load':
+	Action::register('glpi_widget_load',function(&$response){
 		global $myUser;
 		require_once(PLUGIN_PATH.'dashboard'.SLASH.'DashboardWidget.class.php');
 
@@ -37,9 +32,10 @@ switch($_['action']){
 		$widget->content = ob_get_clean();
 
 		echo json_encode($widget);
-	break;
+		exit();
+	});
 	
-	case 'glpi_widget_glpi_configure':
+	Action::register('glpi_widget_glpi_configure',function(&$response){
 		global $myUser;
 		User::check_access('glpi','configure');
 		require_once(PLUGIN_PATH.'dashboard'.SLASH.'DashboardWidget.class.php');
@@ -48,21 +44,17 @@ switch($_['action']){
 		require_once(__DIR__.SLASH.'widget.configure.php');
 		$content = ob_get_clean();
 		echo $content ;
-	break;
+		exit();
+	});
 
-	case 'glpi_widget_glpi_configure_save':
-		Action::write(function(&$response){
+	Action::register('glpi_widget_glpi_configure_save',function(&$response){
 			global $myUser,$_;
 			User::check_access('glpi','configure');
 			require_once(PLUGIN_PATH.'dashboard'.SLASH.'DashboardWidget.class.php');
 			$widget = DashboardWidget::getById($_['id']);
 			$widget->data('service',$_['widget-glpi-service']);
 			$widget->data('newHours',$_['widget-glpi-new-hours']);
-
 			$widget->save();
-		});
-	break;
-
+	});
 
-}
 ?>

+ 5 - 6
plugin/glpi/glpi.plugin.php

@@ -28,10 +28,10 @@ function glpi_uninstall($id){
 //Déclaration des sections de droits du plugin
 Right::register("glpi",array('label'=>"Gestion des droits sur le plugin glpi"));
 
-//cette fonction comprends toutes les actions du plugin qui ne nécessitent pas de vue html
-function glpi_action(){
-	require_once(__DIR__.SLASH.'action.php');
-}
+//Comprends toutes les actions du plugin qui ne nécessitent pas de vue html
+
+require_once(__DIR__.SLASH.'action.php');
+
 
 //Déclaration du menu de réglages
 function glpi_menu_setting(&$settingMenu){
@@ -95,8 +95,7 @@ Plugin::addHook("install", "glpi_install");
 Plugin::addHook("uninstall", "glpi_uninstall"); 
 
 
-Plugin::addHook("page", "glpi_page");  
-Plugin::addHook("action", "glpi_action");  
+Plugin::addHook("page", "glpi_page");    
 Plugin::addHook("menu_setting", "glpi_menu_setting");    
 Plugin::addHook("content_setting", "glpi_content_setting");   
 Plugin::addHook("widget", "glpi_widget");    

+ 1 - 1
plugin/host/Machine.class.php

@@ -30,7 +30,7 @@ class Machine extends Entity{
 		'manager' => array('type'=>'user', 'label' => 'Responsable'),
 		'ip' => array('type'=>'text', 'label' => 'IP Lan'),
 		'client' => array('type'=>'int', 'label' => 'Client'),
-		'os' => array('type'=>'dictionnary', 'label' => 'Système d\'exploitation'),
+		'os' => array('type'=>'dictionary', 'label' => 'Système d\'exploitation'),
 		'mac' => array('type'=>'text', 'label' => 'Adresse MAC'),
 		'ram' => array('type'=>'decimal', 'label' => 'Mémoire Vive (RAM)'),
 		'cpu' => array('type'=>'decimal', 'label' => 'Nb Cœur CPU'),

+ 2 - 2
plugin/host/action.php

@@ -67,7 +67,7 @@
 		$machines = Machine::staticQuery($query,$data,true,1);
 		
 
-		$osList = Dictionnary::slugToArray('host_machine_os',true);
+		$osList = Dictionary::slugToArray('host_machine_os',true);
 		$response['rows'] = array();
 		foreach($machines as $machine){
 			$row = $machine->toArray();
@@ -82,7 +82,7 @@
 			$row['class'] = '';
 			if( !$machine->can('edit')) $row['class'] .= ' readonly ';
 			if(!empty($row['os'])){
-				$row['os'] = isset($osList[$row['os']]) ? $osList[$row['os']] : new Dictionnary(); 
+				$row['os'] = isset($osList[$row['os']]) ? $osList[$row['os']] : new Dictionary(); 
 			}else{
 				unset($row['os']);
 			}

+ 1 - 1
plugin/host/app.json

@@ -6,7 +6,7 @@
 		"mail" : ""
 	},
 	"version": "1.0",
-	"url": "http://sys1.fr",
+	"url": "http://idleman.fr",
 	"licence": {"name": "Copyright","url" : ""},
 	"color": "#d35400",
 	"icon": "fab fa-ubuntu",

+ 14 - 14
plugin/host/host.plugin.php

@@ -32,13 +32,13 @@ function host_install($id){
 	if($id != 'fr.core.host') return;
 	Entity::install(__DIR__);
 
-	$dictionnary = new Dictionnary();
-    	$dictionnary->slug = 'host_machine_os';
-    	if(Dictionnary::rowCount(array('slug'=>$dictionnary->slug)) ==0){
-	    	$dictionnary->label = 'Machine / Environnement : Système d\'exploitation';
-	    	$dictionnary->parent = 0;
-	    	$dictionnary->state = Dictionnary::ACTIVE;
-	    	$dictionnary->save();
+	$dictionary = new Dictionary();
+    	$dictionary->slug = 'host_machine_os';
+    	if(Dictionary::rowCount(array('slug'=>$dictionary->slug)) ==0){
+	    	$dictionary->label = 'Machine / Environnement : Système d\'exploitation';
+	    	$dictionary->parent = 0;
+	    	$dictionary->state = Dictionary::ACTIVE;
+	    	$dictionary->save();
 
 	    	foreach(array(
 	    		'other'=>'Autre',
@@ -50,11 +50,11 @@ function host_install($id){
 	    		'linux_ubuntu'=>'Linux - Ubuntu 22.4',
 	    		'window'=>'Windows server',
 	    	) as $key=>$value){
-		    	$item = new Dictionnary();
+		    	$item = new Dictionary();
 				$item->slug = 'host_machine_os_'.$key;
 				$item->label = $value;
-				$item->parent = $dictionnary->id;
-				$item->state = Dictionnary::ACTIVE;
+				$item->parent = $dictionary->id;
+				$item->state = Dictionary::ACTIVE;
 				$item->save();
 			}
 	    }
@@ -65,10 +65,10 @@ function host_install($id){
 function host_uninstall($id){
 	if($id != 'fr.core.host') return;
 	Entity::uninstall(__DIR__);
-	$dictionnary = Dictionnary::bySlug('host_machine_os');
-    	if($dictionnary!= false && $dictionnary->id!=0){
-    		Dictionnary::delete(array('parent'=>$dictionnary->id));
-    		Dictionnary::delete(array('id'=>$dictionnary->id));
+	$dictionary = Dictionary::bySlug('host_machine_os');
+    	if($dictionary!= false && $dictionary->id!=0){
+    		Dictionary::delete(array('parent'=>$dictionary->id));
+    		Dictionary::delete(array('id'=>$dictionary->id));
     	}
     
 }

+ 1 - 1
plugin/host/page.sheet.machine.php

@@ -101,7 +101,7 @@ if($machine->id==0){
 				<div class="col-md-6">
 					<div class="input-group input-group-sm mt-2">
 						<div class="input-group-prepend"><div class="input-group-text">Os</div></div>
-						<select class="form-control form-control-sm" type="text" data-type="dictionnary" data-slug="host_machine_os" data-depth="1" key=data-disable-label data-value="<?php echo $machine->os; ?>" id="os" ></select>
+						<select class="form-control form-control-sm" type="text" data-type="dictionary" data-slug="host_machine_os" data-depth="1" key=data-disable-label data-value="<?php echo $machine->os; ?>" id="os" ></select>
 					</div>
 				</div>
 			</div>

+ 1 - 1
plugin/host/setting.global.host.php

@@ -16,7 +16,7 @@ User::check_access('host','configure');
 
 	    
     <h4>Systèmes d'exploitation</h4>
-    <div data-type="dictionnary-table" data-dictionnary="host_machine_os"></div>
+    <div data-type="dictionary-table" data-dictionary="host_machine_os"></div>
 	    
     </div>
 

+ 1 - 1
plugin/import/action.php

@@ -454,7 +454,7 @@
 
 					
 					//Si le champ est lié a une autre entité en n-1 (un champs de l'entité courante point vers l'id d'une autre entité)
-					if(isset($entityLinks[$importmapping->entityField]) && basename($entityLinks[$importmapping->entityField])!='Dictionnary.class.php'){
+					if(isset($entityLinks[$importmapping->entityField]) && basename($entityLinks[$importmapping->entityField])!='Dictionary.class.php'){
 						
 						$file = $entityLinks[$importmapping->entityField];
 						require_once(__ROOT__.SLASH.$file);

+ 8 - 8
plugin/import/import.plugin.php

@@ -99,8 +99,8 @@ function import_report_line(&$response,$context,$type,$typeLabel,$message){
 
 function import_import_macros(&$macros){
 	$macros = array(
-			'dictionnary' => array(
-				'slug'=>'dictionnary',
+			'dictionary' => array(
+				'slug'=>'dictionary',
 				'label'=>'Convertir en liste configurable',
 				'description'=>'Convertis les valeurs en dictionnaire (liste configurable)',
 				'mutator'=> function($value,$context = array()){
@@ -109,13 +109,13 @@ function import_import_macros(&$macros){
 					
 					//récuperation du dico racine / construition si inexistant
 					if(!isset($context['dictionnaries'][$parentSlug])){
-						$parent = Dictionnary::bySlug($parentSlug);
+						$parent = Dictionary::bySlug($parentSlug);
 						if(!$parent){
-							$parent = new Dictionnary();
+							$parent = new Dictionary();
 							$parent->slug = $parentSlug;
 							$parent->label = $context['entityLabel'].' : '.$context['entityField']['label']; 
 							$parent->parent = 0;
-							$parent->state = Dictionnary::ACTIVE;
+							$parent->state = Dictionary::ACTIVE;
 							$parent->save();
 						}
 						$context['dictionnaries'][$parentSlug] = array('id'=>$parent->id,'childs'=>array());
@@ -124,13 +124,13 @@ function import_import_macros(&$macros){
 					$valueSlug = $parentSlug.'_'.slugify($value);
 					if(!isset($context['dictionnaries'][$parentSlug]['childs'][$valueSlug])){
 
-						$item = Dictionnary::bySlug($valueSlug);
+						$item = Dictionary::bySlug($valueSlug);
 						if(!$item){
-							$item = new Dictionnary();
+							$item = new Dictionary();
 							$item->slug = $valueSlug;
 							$item->label = $value;
 							$item->parent = $context['dictionnaries'][$parentSlug]['id'];
-							$item->state = Dictionnary::ACTIVE;
+							$item->state = Dictionary::ACTIVE;
 							$item->save();
 						}
 

+ 3 - 3
plugin/import/js/main.js

@@ -152,7 +152,7 @@ function import_mapping_search(callback){
 	
 	$('.entityField').html('');
 	$.action({
-		action : 'entity_attributes',
+		action : 'core_entity_attribute_search',
 		path : entity
 	},function(response){
 		var html = '<option value="">-</option>';
@@ -161,7 +161,7 @@ function import_mapping_search(callback){
 			var field = response.fields[k];
 			html += '<option '+(field.childs?'data-link':'')+' value="'+field.column+'">'+field.label+'</option>';
 			//si l'attribut et lié a une autre entité, on stock les attributs de cette autre entitée en tableau global pour réutilisation dans import_check_foreign_attribute
-			if(field.childs  && field.entity !='Dictionnary'){
+			if(field.childs  && field.entity !='Dictionary'){
 				
 				if(!window.importLinks ) window.importLinks = {};
 				window.importLinks[field.column] = field.childs;
@@ -229,7 +229,7 @@ function import_entity_field_change(element){
 function import_entity_related_change(related){
 	var line = related.closest('tr');
 	$.action({
-		action : 'entity_attributes',
+		action : 'core_entity_attribute_search',
 		path : related.val()
 	},function(response){
 		var relatedField = line.find('.entityRelatedField');

+ 2 - 2
plugin/import/template/CsvImport.class.php

@@ -88,8 +88,8 @@ class CsvImport{
 
 		if(stripos($columnName, 'prix ')===0 || stripos($columnName, 'montant ')===0 || stripos($columnName, 'tarif ')===0 )  $deductedType = 'price';
 		if(stripos($columnName, 'date ')===0)  $deductedType = 'date';
-		if(stripos($columnName, 'catégorie ')===0 || stripos($columnName, 'categorie ')===0 )  $deductedType = 'dictionnary';
-		if(stripos($columnName, 'type ')===0 )  $deductedType = 'dictionnary';
+		if(stripos($columnName, 'catégorie ')===0 || stripos($columnName, 'categorie ')===0 )  $deductedType = 'dictionary';
+		if(stripos($columnName, 'type ')===0 )  $deductedType = 'dictionary';
 		
 
 		return $deductedType;

+ 57 - 60
plugin/issue/action.php

@@ -1,10 +1,9 @@
 <?php
-global $_,$conf;
-switch($_['action']){
+
 	/** ISSUEREPORT **/
 	//Récuperation d'une liste de issuereport
-	case 'issue_issuereport_search':
-		Action::write(function(&$response){
+	Action::register('issue_issuereport_search',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('issue','read');
 			require_once(__DIR__.SLASH.'IssueReport.class.php');
@@ -114,11 +113,11 @@ switch($_['action']){
 				}
 				$response['rows'][] = $row;
 			}
-		});
-	break;
+		
+	});
 
-	case 'issue_autocomplete':
-		Action::write(function(&$response){
+	Action::register('issue_autocomplete',function(&$response){
+	
 		global $myUser,$_;
 		if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
 		require_once(__DIR__.SLASH.'IssueReport.class.php');
@@ -134,23 +133,23 @@ switch($_['action']){
 					'slug' => $row['id']
 				);
 			}
-		});
-	break;
+		
+	});
 
 	//Gestion avatar drag & drop
-	case 'issue_attachments':
-		Action::write(function(&$response){
+	Action::register('issue_attachments',function(&$response){
+	
 			File::handle_component(array(
 				'namespace' => 'issue', //stockés dans file/summary/*.*
 				'access' => 'issue', // crud sur summary,
 				'size' => '1000000000', // taille max
 				'storage' => 'issue/attachments/{{data.id}}/*' //chemin complet vers le fichier stocké
 			),$response);
-		});
-	break;
+		
+	});
 
-	case 'issue_add_document':
-	Action::write(function(&$response){
+	Action::register('issue_add_document',function(&$response){
+	
 		global $myUser,$_;
 		if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
 		require_once(__DIR__.SLASH.'IssueReport.class.php');
@@ -167,11 +166,11 @@ switch($_['action']){
 			$response['files'][] = $row;
 		}
 		$response['id'] = $report->id;
+	
 	});
-	break;
 
 	//Téléchargement des documents
-	case 'issue_download_document':
+	Action::register('issue_download_document',function(&$response){
 		global $myUser,$_;
 		if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
 
@@ -181,10 +180,10 @@ switch($_['action']){
 		$path = str_replace(array('..','/','\\'),'',base64_decode($_['path']));
 		$path = $event->dir().SLASH.$path;
 		File::downloadFile($path);
-	break;
+	});
 
-	case 'issue_issuereport_meta_save':
-		Action::write(function(&$response){
+	Action::register('issue_issuereport_meta_save',function(&$response){
+	
 			global $myUser,$_,$conf;
 
 			User::check_access('issue','edit');
@@ -309,12 +308,12 @@ switch($_['action']){
 				$event->save();
 				Plugin::callHook("emit_notification", array($infos));
 			}
-		});
-	break;
+		
+	});
 	
 	//Ajout ou modification d'élément issuereport
-	case 'issue_issuereport_save':
-		Action::write(function(&$response){
+	Action::register('issue_issuereport_save',function(&$response){
+	
 			global $myUser,$_,$conf;
 			require_once(__DIR__.SLASH.'IssueReport.class.php');
 			require_once(__DIR__.SLASH.'IssueEvent.class.php');
@@ -433,10 +432,10 @@ switch($_['action']){
 			)));
 
 			Log::put('Déclaration d\'un rapport d\'erreur #'.$item->toText(), 'Issue');
-		});
-	break;
+		
+	});
 	
-	case 'issue_screenshot_download':
+	Action::register('issue_screenshot_download',function(&$response){
 		global $myUser,$_;
 		if(!$myUser->connected()) throw new Exception("Connexion requise",401);
 		try {
@@ -446,25 +445,23 @@ switch($_['action']){
 		} catch(Exception $e) {
 			File::downloadFile(__ROOT__.'img/default-image.png');
 		}
-	break;
+	});
 
 	//Suppression d'élement issuereport
-	case 'issue_issuereport_delete':
-		Action::write(function(&$response){
+	Action::register('issue_issuereport_delete',function(&$response){
+	
 			global $myUser,$_;
-			
 			require_once(__DIR__.SLASH.'IssueReport.class.php');
 			require_once(__DIR__.SLASH.'IssueEvent.class.php');
-			
 			$issue = IssueReport::provide();
 			if($issue->creator != $myUser->login && !$myUser->can('issue','configure')) throw new Exception("Permissions insuffisantes", 403);
 			$issue->remove();
-		});
-	break;
+		
+	});
 
 	//Etre notifié du sujet
-	case 'issue_follow_toggle':
-		Action::write(function(&$response){
+	Action::register('issue_follow_toggle',function(&$response){
+	
 			global $myUser,$_;
 			require_once(__DIR__.SLASH.'IssueReport.class.php');
 			require_once(__DIR__.SLASH.'IssueEvent.class.php');
@@ -482,12 +479,12 @@ switch($_['action']){
 
 			$issue->followers($followers);
 			$issue->save();
-		});
-	break;
+		
+	});
 	
 	//Sauvegarde des configurations de issue
-	case 'issue_setting_save':
-		Action::write(function(&$response){
+	Action::register('issue_setting_save',function(&$response){
+	
 			global $myUser,$_,$conf;
 			User::check_access('issue','configure');
 			foreach(Configuration::setting('issue') as $key=>$value){
@@ -496,14 +493,14 @@ switch($_['action']){
 			}
 			foreach ($_['fields'] as $key => $value)
 				if(in_array($key, $allowed)) $conf->put($key,$value);
-		});
-	break;
+		
+	});
 
 
 	/** EVENT **/
 	//Récuperation d'une liste de issueevent
-	case 'issue_issue_event_search':
-		Action::write(function(&$response){
+	Action::register('issue_issue_event_search',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('issue','read');
 			require_once(__DIR__.SLASH.'IssueEvent.class.php');
@@ -562,12 +559,12 @@ switch($_['action']){
 				}
 				$response['rows'][] = $row;
 			}
-		});
-	break;
+		
+	});
 	
 	//Ajout ou modification d'élément issueevent
-	case 'issue_issue_event_save':
-		Action::write(function(&$response){
+	Action::register('issue_issue_event_save',function(&$response){
+	
 			global $myUser,$_;
 			require_once(__DIR__.SLASH.'IssueReport.class.php');
 			require_once(__DIR__.SLASH.'IssueEvent.class.php');
@@ -633,12 +630,12 @@ switch($_['action']){
 				)));
 			}
 
-		});
-	break;
+		
+	});
 	
 	//Récuperation ou edition d'élément issueevent
-	case 'issue_issue_event_edit':
-		Action::write(function(&$response){
+	Action::register('issue_issue_event_edit',function(&$response){
+	
 			global $myUser,$_;
 			User::check_access('issue','edit');
 			require_once(__DIR__.SLASH.'IssueEvent.class.php');
@@ -648,12 +645,12 @@ switch($_['action']){
 			if($event->type != 'comment') throw new Exception("Vous ne pouvez pas éditer cet événement");
 			if($myUser->login != $event->creator && !$myUser->superadmin) throw new Exception("Permissions insuffisantes", 403);
 			$response = $event->toArray(true);
-		});
-	break;
+		
+	});
 
 	//Suppression d'élement issueevent
-	case 'issue_issue_event_delete':
-		Action::write(function(&$response){
+	Action::register('issue_issue_event_delete',function(&$response){
+	
 			global $myUser,$_;
 			require_once(__DIR__.SLASH.'IssueReport.class.php');
 			require_once(__DIR__.SLASH.'IssueEvent.class.php');
@@ -670,7 +667,7 @@ switch($_['action']){
 				$issue->remove(false);
 				$response['redirect'] = 'index.php?module=issue&page=list.issue';
 			}
-		});
-	break;
-}
+		
+	});
+
 ?>

+ 4 - 5
plugin/issue/issue.plugin.php

@@ -32,10 +32,9 @@ function issue_uninstall($id){
 Right::register('issue',array('label'=>'Gestion des droits sur le plugin issue'));
 
 
-//cette fonction comprends toutes les actions du plugin qui ne nécessitent pas de vue html
-function issue_action(){
-	require_once(__DIR__.SLASH.'action.php');
-}
+//Comprends toutes les actions du plugin qui ne nécessitent pas de vue html
+require_once(__DIR__.SLASH.'action.php');
+
 
 //Déclaration du menu de réglages
 function issue_menu_setting(&$settingMenu){
@@ -119,7 +118,7 @@ Plugin::addHook("uninstall", "issue_uninstall");
 
 Plugin::addHook("page", "issue_page");   
 Plugin::addHook("application_bottom", "issue_modal");   
-Plugin::addHook("action", "issue_action");  
+  
 Plugin::addHook("menu_setting", "issue_menu_setting");    
 Plugin::addHook("content_setting", "issue_content_setting");   
 Plugin::addHook("menu_user", "issue_menu_user");

+ 31 - 5
plugin/navigation/MenuItem.class.php

@@ -71,9 +71,18 @@ class MenuItem extends Entity{
 
 		$mainMenu = array();
 
-		//$firm
-		$query = 'SELECT it.* FROM {{table}} it LEFT JOIN {{table}} me ON it.menu=me.id WHERE me.slug=? and me.user=? ';
-		$data = array($menuSlug,$user);
+		
+		$query = 'SELECT it.*,me.slug as parentSlug FROM {{table}} it LEFT JOIN {{table}} me ON it.menu=me.id WHERE me.user=?';
+		$data = array($user);
+		
+		if(is_array($menuSlug)){
+
+			$query .= ' AND me.slug IN ('.implode(',',array_fill(0,count($menuSlug),'?')).') ';
+			foreach($menuSlug as $slug) $data[] = $slug;
+		}else{
+			$query .= ' AND me.slug=? ';
+			$data[] = $menuSlug;
+		}
 
 		if(!empty($firms)){
 			$query .=' AND it.firm IN ('.implode(',',array_fill(0, count($firms), '?')).') ';
@@ -83,8 +92,11 @@ class MenuItem extends Entity{
 
 		$query .= ' ORDER BY sort';
 
+		
 		foreach(self::staticQuery($query,$data ,true) as $dbItem){
-			$mainMenu[] = $dbItem->toArray(); 
+			$item = $dbItem->toArray();
+			$item['foreign'] = $dbItem->foreign();
+			$mainMenu[] = $item; 
 		}
 
 		uasort ($mainMenu , function($a,$b){return $a['sort']>$b['sort']?1:-1;});
@@ -100,7 +112,21 @@ class MenuItem extends Entity{
 		}
 
 		
-		return $menuItems;
+		if(is_array($menuSlug)){
+			//tri par slug
+			$menuItemsBySlug = array();
+			foreach($menuSlug as $slug){
+				$menuItemsBySlug[$slug] = array();
+				foreach($menuItems as $item){
+					if($item['foreign']['parentSlug']!=$slug) continue;
+					$menuItemsBySlug[$slug][] = $item;
+				}
+			}
+			return $menuItemsBySlug;
+		}else{
+			return $menuItems;
+		}
+		
 	}
 
 

+ 6 - 3
plugin/navigation/navigation.plugin.php

@@ -4,13 +4,14 @@ require_once(__DIR__.SLASH.'action.php');
 //Déclaration d'un item de menu dans le menu principal
 function navigation_menu(){
 	require_once(__DIR__.SLASH.'MenuItem.class.php');
-	global $myUser,$conf,$myFirm;
+	global $myUser,$conf,$myFirm,$menu;
 
 
+	$menu = MenuItem::bySlug(array('footer-menu','main-menu'),'',array($myFirm->id,0));
 
 ?>
 	<ul class="navbar-nav navigation-menu">
-		<?php foreach(MenuItem::bySlug('main-menu','',array($myFirm->id,0) ) as $item):
+		<?php foreach($menu['main-menu'] as $item):
 			navigation_item_template($item);
 		endforeach; ?>
 	</ul>
@@ -27,8 +28,10 @@ function navigation_menu(){
 }
 
 function navigation_menu_footer(&$items){
+	global $menu;
 	require_once(__DIR__.SLASH.'MenuItem.class.php');
-	$items = array_merge($items,MenuItem::bySlug('footer-menu'));
+	$items = $menu['footer-menu'];
+	//$items = array_merge($items,MenuItem::bySlug('footer-menu'));
 }
 
 function navigation_item_template($item){

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно