action.php 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506
  1. <?php
  2. if(!ini_get('safe_mode')) @set_time_limit(0);
  3. require_once __DIR__.DIRECTORY_SEPARATOR."common.php";
  4. if(php_sapi_name() == 'cli'){
  5. array_shift($_SERVER['argv']);
  6. $_['action'] = array_shift($_SERVER['argv']);
  7. foreach ($_SERVER['argv'] as $keyvalue) {
  8. $infos = explode('=',$keyvalue);
  9. $key = $infos[0];
  10. $value = count($infos)<2 ? '' : $infos[1];
  11. $_[$key] = $value;
  12. }
  13. }
  14. if(!isset($_['action'])) throw new Exception('Action inexistante');
  15. Action::register('login',function(&$response){
  16. global $myUser,$myFirm,$_,$conf;
  17. try {
  18. if(!isset($_['login'])) $_['login'] = 'anonymous';
  19. if(!isset($_['password'])) $_['password'] = '';
  20. Log::put("Tentative de connexion avec le login \"".$_['login']."\"",'Utilisateur');
  21. if($conf->get('account_block')==1){
  22. $try = is_numeric($conf->get('account_block_try')) ? $conf->get('account_block_try') : 5;
  23. $delay = is_numeric($conf->get('account_block_delay')) ? $conf->get('account_block_delay') : 10;
  24. $trying = Log::loadAll(array('category'=>'auth_fail', 'label'=>$_['login'], 'created:>'=>(time() - ($delay*60))));
  25. if(count($trying)>=$try) throw new Exception("Suite à un trop grand nombre de tentatives, votre compte est bloqué pour un délai de ".$delay." minutes",509);
  26. }
  27. $myUser = User::check($_['login'],html_entity_decode($_['password']));
  28. if(!$myUser) throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur");
  29. if(file_exists('enabled.maintenance') && $myUser->superadmin != 1) throw new Exception('Seul un compte Super Admin peut se connecter en mode maintenance');
  30. if(!$myUser->connected()) throw new Exception('Identifiant ou mot de passe incorrect');
  31. //Suppression du token de reset de password s'il se reconnecte entre temps
  32. UserPreference::delete(array('user'=>$myUser->login,'key'=>'lost_password'));
  33. $myUser->loadPreferences();
  34. if(is_numeric($myUser->preference('default_firm')) && $myUser->haveFirm($myUser->preference('default_firm'))){
  35. $_SESSION['firm'] = serialize(Firm::getById($myUser->preference('default_firm')));
  36. if(!$_SESSION['firm']) throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur");
  37. } else if(count($myUser->firms)!=0) {
  38. $_SESSION['firm'] = serialize(reset($myUser->firms));
  39. if(!$_SESSION['firm']) throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur");
  40. } else {
  41. throw new Exception('Ce compte n\'est actif sur aucun établissement');
  42. }
  43. $myFirm = isset($_SESSION['firm']) ? unserialize($_SESSION['firm']) : new Firm();
  44. if(!$myFirm) throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur");
  45. $_SESSION['currentUser'] = serialize($myUser);
  46. if(!$_SESSION['currentUser']) throw new Exception("Problème lors de la connexion, veuillez contacter l'administrateur");
  47. //Gestion de l'inactivité de l'utilisateur
  48. $inactivityDelay = $conf->get('logout_inactivity_delay');
  49. if(!empty($inactivityDelay) && is_numeric($inactivityDelay)){
  50. $response['inactivityDelay'] = $inactivityDelay;
  51. $myUser->meta['lastActivity'] = time();
  52. }
  53. if(isset($_['rememberMe']) && $_['rememberMe']){
  54. $cookie = password_hash(mt_rand(0,1000000000000).uniqid("", true).mt_rand(0,1000000000000), PASSWORD_DEFAULT);
  55. $myUser->preference('cookie',$cookie);
  56. make_cookie(COOKIE_NAME, $cookie);
  57. } else {
  58. $myUser->preference('cookie','');
  59. }
  60. $response['redirect'] = isset($_['url']) ? base64_decode($_['url']) : 'index.php';
  61. if(isset($_SESSION['last_request']) && !isset($_['url'])){
  62. $response['redirect'] = $_SESSION['last_request'];
  63. unset($_SESSION['last_request']);
  64. }
  65. Plugin::callHook('user_logged',array(&$myUser));
  66. //permet la redirection classic pour certains plugin d'authentification qui ne passent pas par le formulaire ajax
  67. if(isset($_['redirect']) && $_['redirect']=='classic'){
  68. header('location: '. $response['redirect']);
  69. exit();
  70. }
  71. Log::put("Connexion réussie avec \"".$myUser->login."\"",'Utilisateur');
  72. } catch(Exception $e){
  73. Log::put("Échec de la connexion avec ".$_['login']." : ".$e->getMessage(),'Utilisateur');
  74. //La vérification sur le code 509 permet d'éviter d'allonger le temps de ban à chaque tentative
  75. if($e->getCode()!=509) Log::put($_['login'],'auth_fail');
  76. throw new Exception($e->getMessage());
  77. }
  78. });
  79. Action::register('logout',function(&$response){
  80. global $myUser,$_;
  81. $url = $myUser->disconnect(isset($_['url'])?$_['url']:null);
  82. Plugin::callHook('logout',array($url,$myUser));
  83. $response['redirect'] = $url;
  84. });
  85. Action::register('initialize_activity',function(&$response){
  86. global $myUser;
  87. if(!$myUser->connected()) throw new Exception("Permission non accordée");
  88. $myUser->meta['lastActivity'] = time();
  89. });
  90. /** DYNAMIC COLUMNS **/
  91. Action::register('fill_colum_save',function(&$response){
  92. global $myUser,$_;
  93. if(!$myUser->connected()) return;
  94. $preferences = json_decode($myUser->preference('search_columns'),true);
  95. if(!$preferences) $preferences = array();
  96. if(!isset($_['slug'])) return $response;
  97. if(empty($_['added'])) $_['added'] = array();
  98. $preferences[$_['slug']] = $_['added'];
  99. $myUser->preference('search_columns',json_encode($preferences));
  100. $_SESSION['currentUser'] = serialize($myUser);
  101. });
  102. Action::register('fill_column_load',function(&$response){
  103. global $myUser,$_;
  104. if(!isset($myUser)) throw new Exception("Utilisateur non définis");
  105. $response = json_decode($myUser->preference('search_columns'),true);
  106. if(!$response) $response = array();
  107. return $response;
  108. });
  109. /** FILTERS **/
  110. Action::register('filter_save',function(&$response){
  111. global $myUser,$_;
  112. if(!$myUser->connected()) throw new Exception("Permission non accordée");
  113. $preferences = json_decode($myUser->preference('search_filters'),true);
  114. if(!$preferences) $preferences = array();
  115. if(!isset($_['slug'])) return $response;
  116. if(empty($_['label'])) throw new Exception("Libellé obligatoire");
  117. function filter_recursive_save($filters){
  118. foreach($filters as $i=>$advanced){
  119. if(isset($filters[$i]['operator'])) $filters[$i]['operator'] = html_entity_decode($filters[$i]['operator']);
  120. if(isset($filters[$i]['group'])) $filters[$i]['group'] = filter_recursive_save($filters[$i]['group']);
  121. if(!isset($filters[$i]['value'])) continue;
  122. foreach($filters[$i]['value'] as $j => $value)
  123. $filters[$i]['value'][$j] = html_entity_decode($value,ENT_QUOTES,'UTF-8');
  124. }
  125. return $filters;
  126. }
  127. if(isset($_['filters']['keyword'])) $_['filters']['keyword'] = html_entity_decode($_['filters']['keyword'],ENT_QUOTES,'UTF-8');
  128. if(isset($_['filters']['advanced'])) $_['filters']['advanced'] = filter_recursive_save($_['filters']['advanced']);
  129. if(!isset($preferences[$_['slug']])) $preferences[$_['slug']] = array();
  130. $_['label'] = html_entity_decode($_['label'],ENT_QUOTES,'UTF-8');
  131. $uid = base64_encode($_['label']);
  132. $preferences[$_['slug']][$uid] = array(
  133. 'label' => $_['label'],
  134. 'uid' => $uid,
  135. 'filters'=> $_['filters']
  136. );
  137. $myUser->preference('search_filters',json_encode($preferences));
  138. $response['message'] = 'Recherche enregistrée';
  139. $_SESSION['currentUser'] = serialize($myUser);
  140. });
  141. Action::register('filter_remove',function(&$response){
  142. global $myUser,$_;
  143. if(!$myUser->connected()) throw new Exception("Pemrission denied");
  144. if(!$myUser->superadmin && isset($_['global']) && !empty($_['global'])) throw new Exception("Impossible de supprimer une recherche partagée");
  145. $preferences = json_decode($myUser->preference('search_filters'),true);
  146. unset($preferences[$_['slug']][$_['uid']]);
  147. $myUser->preference('search_filters',json_encode($preferences));
  148. $_SESSION['currentUser'] = serialize($myUser);
  149. });
  150. Action::register('filter_save_global',function(&$response){
  151. global $myUser,$_,$conf;
  152. if((empty($_['rightSection']) && !$myUser->superadmin) || (isset($_['rightSection']) && !$myUser->can($_['rightSection'], 'configure'))) throw new Exception("Permissions insuffisantes", 403);
  153. if(empty($_['slug']) || empty($_['uid'])) return $response;
  154. $globalPreferences = json_decode($conf->get('search_filters'),true);
  155. $preferences = json_decode($myUser->preference('search_filters'),true);
  156. if($_['state']==1){
  157. $globalPreferences[$_['slug']][$_['uid']] = $preferences[$_['slug']][$_['uid']];
  158. unset($preferences[$_['slug']][$_['uid']]);
  159. }else{
  160. $preferences[$_['slug']][$_['uid']] = $globalPreferences[$_['slug']][$_['uid']];
  161. unset($globalPreferences[$_['slug']][$_['uid']]);
  162. }
  163. $conf->put('search_filters',json_encode($globalPreferences));
  164. $myUser->preference('search_filters',json_encode($preferences));
  165. $_SESSION['currentUser'] = serialize($myUser);
  166. });
  167. Action::register('filter_load',function(&$response){
  168. global $myUser,$_,$conf;
  169. if(!isset($myUser)) throw new Exception("Utilisateur non définis");
  170. if(empty($_['slug'])) return $response;
  171. $searches = array();
  172. $globalPreferences = json_decode($conf->get('search_filters'),true);
  173. $preferences = json_decode($myUser->preference('search_filters'),true);
  174. if(is_array($preferences) && isset($preferences[$_['slug']])){
  175. foreach($preferences[$_['slug']] as $preference){
  176. if(!isset($preference['label'])) continue;
  177. $preference['global'] = 0;
  178. $searches[$preference['uid']] = $preference;
  179. }
  180. }
  181. if(is_array($globalPreferences ) && isset($globalPreferences[$_['slug']])){
  182. foreach($globalPreferences[$_['slug']] as $preference){
  183. if(!isset($preference['label'])) continue;
  184. $preference['global'] = 1;
  185. $searches[$preference['uid']] = $preference;
  186. }
  187. }
  188. $response['filters'] = $searches;
  189. });
  190. /** LOGS */
  191. Action::register('search_log',function(&$response){
  192. global $myUser,$_;
  193. User::check_access('log','read');
  194. $limit = isset($_['export']) && $_['export'] == 'true' ? 5000 : 150;
  195. $data = array();
  196. $query = 'SELECT * FROM {{table}} WHERE 1';
  197. //Recherche simple
  198. if(!empty($_['filters']['keyword'])){
  199. $query .= ' AND label LIKE ?';
  200. $data[] = '%'.$_['filters']['keyword'].'%';
  201. }
  202. //Recherche avancée
  203. if(isset($_['filters']['advanced'])) filter_secure_query($_['filters']['advanced'],array('label','category','creator','created','ip'),$query,$data);
  204. //Tri des colonnes
  205. if(isset($_['sort']))
  206. sort_secure_query($_['sort'],array('label','ip','created','category','creator'),$query,$data);
  207. else
  208. $query .= ' ORDER BY created DESC, id DESC ';
  209. //Pagination
  210. $response['pagination'] = Log::paginate($limit,(!empty($_['page'])?$_['page']:0),$query,$data);
  211. foreach(Log::staticQuery($query,$data,true) as $log){
  212. $row = $log->toArray(true);
  213. $row['created'] = date('d/m/Y H:i:s', $log->created);
  214. $row['created_full'] = date('Y-m-d', $log->created);
  215. if(!empty($_['filters']['keyword'])){
  216. $row['label'] = preg_replace_callback('|(.*)('.$_['filters']['keyword'].')(.*)|i', function($matches){
  217. return $matches[1].'<mark><strong>'.$matches[2].'</strong></mark>'.$matches[3];
  218. }, htmlentities($log->label, ENT_QUOTES));
  219. }
  220. $response['rows'][] = $row;
  221. }
  222. //Export des données
  223. if(isset($_['export']) && $_['export'] == 'true') {
  224. //Clear des marqueurs HTML
  225. foreach($response['rows'] as $i => $row) {
  226. $row['label'] = html_entity_decode(strip_tags($row['label']));
  227. $response['rows'][$i] = $row;
  228. }
  229. $mapping = array(
  230. 'Date' => array('slug'=>'created_full', 'type'=>'DD/MM/YYYY'),
  231. 'Catégorie' => 'category',
  232. 'Libellé' => 'label',
  233. 'Utilisateur' => 'creator',
  234. 'Ip' => 'ip',
  235. );
  236. $export = Excel::exportArray($response['rows'], $mapping, 'Logs');
  237. File::downloadStream($export,'export-logs-'.date('ymd').'.xlsx');
  238. Log::put("Export logs : ".(isset($_['filters']) ? " Filtres: ".json_encode($_['filters']) : '').", Tri: ".(isset($_['sort'])?json_encode($_['sort']):'').", Page: ".$_['page'],'Produit');
  239. exit();
  240. }
  241. });
  242. /** PLUGINS & ENTITEES **/
  243. Action::register('search_plugin',function(&$response){
  244. global $myUser,$_;
  245. User::check_access('plugin','read');
  246. $includeCore = isset($_['includeCore']) && $_['includeCore']==true ;
  247. foreach(Plugin::getAll(false,$includeCore) as $plugin){
  248. $plugin->folder = array('name'=>$plugin->folder,'path'=>$plugin->path());
  249. foreach($plugin->require as $id=>$version)
  250. $plugin->required[] = array('id'=>$id, 'version'=>$version);
  251. $response['rows'][] = $plugin;
  252. }
  253. });
  254. //Récuperation d'une liste d'entitées en fonction du plugin ciblé
  255. Action::register('search_entities',function(&$response){
  256. global $myUser,$_;
  257. if(!$myUser->connected()) throw new Exception("Permission refusée");
  258. if(empty($_['plugin'])) throw new Exception('Plugin non spécifié');
  259. foreach(glob($_['plugin'].SLASH.'*.class.php') as $file){
  260. require_once($file);
  261. $class = str_replace('.class.php','',basename($file));
  262. if(!is_subclass_of($class, 'Entity')) continue;
  263. $instance = new $class();
  264. $label = $class;
  265. $table = strtolower($class);
  266. if(property_exists($instance,'entityLabel') && !empty($instance->entityLabel)) $label = $instance->entityLabel;
  267. if(method_exists($instance,'tableName') && !empty($instance->tableName())) $table = $instance->tableName();
  268. $response['rows'][] = array(
  269. 'class'=> $class,
  270. 'label'=> $label,
  271. 'table'=> $table ,
  272. 'path' => $file
  273. );
  274. }
  275. });
  276. //Récuperation des infos générales d'une entitée
  277. Action::register('entity_edit',function(&$response){
  278. global $myUser,$_;
  279. if(!$myUser->connected()) throw new Exception("Permission refusée");
  280. if(empty($_['path'])) throw new Exception('Chemin non spécifié');
  281. $file = $_['path'];
  282. require_once($file);
  283. $class = str_replace('.class.php','',basename($file));
  284. if(!is_subclass_of($class, 'Entity')) return;
  285. $instance = new $class();
  286. $label = $class;
  287. $table = strtolower($class);
  288. if(property_exists($instance,'entityLabel') && !empty($instance->entityLabel)) $label = $instance->entityLabel;
  289. if(method_exists($instance,'tableName') && !empty($instance->tableName())) $table = $instance->tableName();
  290. $response = array(
  291. 'class'=> $class,
  292. 'label'=> $label,
  293. 'table'=> $table ,
  294. 'path' => $file,
  295. 'plugin' => Plugin::parseManifest(dirname($file).SLASH.'app.json')
  296. );
  297. });
  298. //Récuperation de la liste des attributs d'une entitée
  299. Action::register('entity_attributes',function(&$response){
  300. global $myUser,$_;
  301. if(!$myUser->connected()) throw new Exception("Permission refusée");
  302. if(empty($_['path'])) throw new Exception('Chemin non spécifié');
  303. $file = $_['path'];
  304. require_once($file);
  305. $class = str_replace('.class.php','',basename($file));
  306. if(!is_subclass_of($class, 'Entity')) return;
  307. $instance = new $class();
  308. $fields = $instance->fields(false);
  309. if(property_exists($instance,'links')){
  310. foreach($instance->links as $field=>$classFile){
  311. $classFile = __ROOT__.SLASH.$classFile;
  312. if(!file_exists($classFile)) continue;
  313. require_once($classFile);
  314. $subClass = str_replace('.class.php','',basename($classFile));
  315. if(!is_subclass_of($subClass, 'Entity')) continue;
  316. $subInstance = new $subClass();
  317. $fields[$field]['entity'] = $subClass;
  318. $fields[$field]['classFile'] = $classFile;
  319. $fields[$field]['childs'] = $subInstance->fields(false);
  320. }
  321. };
  322. $response['fields'] = $fields;
  323. });
  324. Action::register('change_plugin_state',function(&$response){
  325. global $myUser,$_;
  326. User::check_access('plugin','configure');
  327. $plugin = Plugin::getById($_['plugin']);
  328. if($_['state']){
  329. $states = Plugin::states();
  330. $missingRequire = array();
  331. foreach($plugin->require as $require=>$version):
  332. $req = Plugin::getById($require);
  333. if($req == null || $req==false || !$req->state || $req->version!=$version)
  334. $missingRequire[]= $require.' - '.$version;
  335. endforeach;
  336. if(count($missingRequire)!=0) throw new Exception("Plugins pré-requis non installés : ".implode(',',$missingRequire));
  337. }
  338. Plugin::state($_['plugin'],$_['state']);
  339. Log::put(($_['state']?'Activation':'Désactivation')." du plugin ".$_['plugin'],'Plugin');
  340. });
  341. /** LIEN ETABLISSEMENT / PLUGIN **/
  342. Action::register('search_firm_plugin',function(&$response){
  343. global $myUser,$_;
  344. User::check_access('plugin','configure');
  345. if(!isset($_['firm'])) throw new Exception("Établissement non spécifié");
  346. $wholePlugins = array();
  347. if($_['firm'] == '0'){
  348. foreach(Firm::loadAll() as $firm){
  349. foreach(Plugin::getAll(true) as $plugin){
  350. $wholePlugins[$plugin->id][$firm->id] = in_array($firm->id, $plugin->firms) ? 1 : 0;
  351. }
  352. }
  353. }
  354. foreach(Plugin::getAll(true) as $plugin){
  355. if($_['firm'] == '0'){
  356. $plugin->state = count(array_unique($wholePlugins[$plugin->id])) === 1 ? end($wholePlugins[$plugin->id]) : 2;
  357. }else{
  358. $plugin->state = in_array($_['firm'], $plugin->firms) ? 1 : 0;
  359. }
  360. $response['rows'][] = $plugin;
  361. }
  362. });
  363. Action::register('toggle_firm_plugin',function(&$response){
  364. global $myUser,$_;
  365. User::check_access('plugin','configure');
  366. $firms = Firm::loadAll();
  367. $firms[] = Firm::anonymous_firm();
  368. foreach($firms as $firm){
  369. if($firm->id != $_['firm'] && $_['firm'] != '0') continue;
  370. $states = Plugin::states();
  371. $firms = $states[$_['plugin']];
  372. $key = array_search($firm->id, $firms);
  373. if($_['state']==0 && $key !== false){
  374. unset($firms[$key]);
  375. }else if($_['state']==1 && $key === false){
  376. $firms[] = $firm->id;
  377. }
  378. $states[$_['plugin']] = array_values($firms);
  379. Plugin::states($states);
  380. }
  381. });
  382. /** ETABLISSEMENT */
  383. //Récuperation d'une liste de etablissement
  384. Action::register('core_firm_search',function(&$response){
  385. global $_;
  386. User::check_access('firm','read');
  387. // OPTIONS DE RECHERCHE, A ACTIVER POUR UNE RECHERCHE AVANCEE
  388. $query = 'SELECT main.* FROM '.Firm::tableName().' main WHERE 1';
  389. $data = array();
  390. //Recherche simple
  391. if(!empty($_['filters']['keyword'])){
  392. $query .= ' AND main.label LIKE ?';
  393. $data[] = '%'.$_['filters']['keyword'].'%';
  394. }
  395. //Recherche avancée
  396. if(isset($_['filters']['advanced'])) filter_secure_query($_['filters']['advanced'],array('main.label','main.description','main.logo','main.mail','main.phone','main.fax','main.street','main.street2','main.city','main.zipcode','main.siret','main.iban'),$query,$data);
  397. //Tri des colonnes
  398. if(isset($_['sort'])) sort_secure_query($_['sort'],array('main.label','main.description','main.logo','main.mail','main.phone','main.fax','main.street','main.street2','main.city','main.zipcode','main.siret','main.iban'),$query,$data);
  399. //Pagination
  400. //Par défaut pour une recherche, 20 items, pour un export 5000 max
  401. $itemPerPage = !empty($_['itemPerPage']) ? $_['itemPerPage'] : 20;
  402. //force le nombre de page max a 50 coté serveur
  403. $itemPerPage = $itemPerPage>50 ? 50 : $itemPerPage;
  404. if($_['export'] == 'true') $itemPerPage = 5000;
  405. $response['pagination'] = Firm::paginate($itemPerPage,(!empty($_['page'])?$_['page']:0),$query,$data,'main');
  406. $firms = Firm::staticQuery($query,$data,true,0);
  407. $response['rows'] = array();
  408. foreach($firms as $firm){
  409. $row = $firm->toArray();
  410. $row['description'] = html_entity_decode($row['description']);
  411. $row['logo'] = $firm->logo('url');
  412. if($_['export'] == 'true'){
  413. $row['created'] = date('d-m-Y',$row['created']);
  414. $row['updated'] = date('d-m-Y',$row['updated']);
  415. }
  416. $response['rows'][] = $row;
  417. }
  418. /* Mode export */
  419. if($_['export'] == 'true'){
  420. if(empty($response['rows'])) $response['rows'][] = array('Vide'=>'Aucune données');
  421. $fieldsMapping = array();
  422. foreach (Firm::fields(false) as $key => $value)
  423. $fieldsMapping[$value['label']] = $key;
  424. $stream = Excel::exportArray($response['rows'],$fieldsMapping ,'Export');
  425. File::downloadStream($stream,'export-etablissements-'.date('d-m-Y').'.xlsx');
  426. exit();
  427. }
  428. });
  429. //Ajout ou modification d'élément etablissement
  430. Action::register('core_firm_save',function(&$response){
  431. global $_;
  432. User::check_access('firm','edit');
  433. $item = Firm::provide();
  434. $item->label = $_['label'];
  435. $item->description = $_['description'];
  436. $item->mail = $_['mail'];
  437. $item->phone = $_['phone'];
  438. $item->fax = $_['fax'];
  439. $item->street = $_['street'];
  440. $item->street2 = $_['street2'];
  441. $item->city = $_['city'];
  442. $item->zipcode = $_['zipcode'];
  443. $item->siret = $_['siret'];
  444. $item->iban = $_['iban'];
  445. $item->save();
  446. //Ajout upload Logo
  447. if(!empty($_['logo']))
  448. File::save_component('logo', 'core/public/firm/'.$item->id.'/logo.{{extension}}');
  449. $response = $item->toArray();
  450. });
  451. //Suppression d'élement etablissement
  452. Action::register('core_firm_delete',function(&$response){
  453. global $_;
  454. User::check_access('firm','delete');
  455. if(empty($_['id']) || !is_numeric($_['id'])) throw new Exception("Identifiant incorrect");
  456. $firm = Firm::getById($_['id']);
  457. Firm::deleteById($firm->id);
  458. //Suppression de l'établissmeent supprimé dans les plugins activés
  459. $states = Plugin::states();
  460. foreach ($states as $plugin => $firms) {
  461. $key = array_search($_['id'], $firms);
  462. if($key === false) continue;
  463. unset($firms[$key]);
  464. $states[$plugin] = array_values($firms);
  465. }
  466. Plugin::states($states);
  467. //Suppression des liens UFR et des droits associés
  468. UserFirmRank::delete(array('firm'=>$_['id']));
  469. Right::delete(array('firm'=>$_['id']));
  470. Log::put("Suppression de l'établissement ".$firm->toText(),'Etablissement');
  471. });
  472. //Firm : Gestion upload Logo
  473. Action::register('core_firm_logo',function(&$response){
  474. File::handle_component(array(
  475. 'namespace' => 'core', //stockés dans file/core/*.*
  476. 'access' => 'core', // crud sur core,
  477. 'size' => '1000000000', // taille max
  478. 'limit' => '1', // nb max de fichiers
  479. 'storage' => 'core/public/firm/{{data.id}}/logo.*' //chemin complet vers le fichier stocké
  480. ),$response);
  481. });
  482. Action::register('core_firm_select',function(&$response){
  483. global $myUser,$_,$myFirm;
  484. try{
  485. if(!$myUser->connected()) throw new Exception("Permission denied");
  486. if(!$myUser->haveFirm( $_['firm'])) throw new Exception("Vous n'avez pas accès à cet établissement");
  487. $myFirm = Firm::getById($_['firm']);
  488. $_SESSION['firm'] = serialize($myFirm);
  489. $myUser->preference('default_firm',$myFirm->id);
  490. $myUser->loadRights();
  491. $_SESSION['currentUser'] = serialize($myUser);
  492. if(isset($_SESSION['users_rights'])) unset($_SESSION['users_rights']);
  493. if(isset($_SESSION['users_norights'])) unset($_SESSION['users_norights']);
  494. header('location: index.php');
  495. }catch(Exception $e){
  496. header('location: index.php?error='.urlencode($e->getMessage()));
  497. }
  498. });
  499. Action::register('firm_autocomplete',function(&$response){
  500. global $myUser,$_;
  501. if(!$myUser->can('firm','read')) throw new Exception("Vous n'avez pas acces aux établissements");
  502. $response['rows'] = array();
  503. if($_['keyword'] == '') return;
  504. foreach(Firm::loadAll(array('label:like'=> '%'.$_['keyword'].'%' ),array('label')) as $firm){
  505. $response['rows'][] = array(
  506. 'label'=>$firm->label,
  507. 'id'=>$firm->id,
  508. 'description'=>$firm->description
  509. );
  510. }
  511. });
  512. Action::register('firm_by_uid',function(&$response){
  513. global $myUser,$_;
  514. if(!$myUser->can('firm','read')) throw new Exception("Vous n'avez pas acces aux établissements");
  515. $response['items'] = array();
  516. $firms = $_['items'];
  517. foreach(Firm::loadAll(array('id:IN'=>implode(',',$firms))) as $item){
  518. $row = $item->toArray();
  519. $row['label'] = $item->label;
  520. $row['id'] = $item->id;
  521. $response['items'][$item->id] = $row;
  522. }
  523. });
  524. /** LIEN ETABLISSEMENT / UTILISATEUR / RANG **/
  525. Action::register('search_userfirmrank',function(&$response){
  526. global $myUser,$_;
  527. User::check_access('rank','read');
  528. $firms = array($_['firm']);
  529. if($_['firm'] == 0){
  530. $firms = array();
  531. foreach(Firm::loadAll() as $firm)
  532. $firms[] = $firm->id;
  533. }
  534. $users = array();
  535. foreach(User::getAll(array('right'=>false)) as $user)
  536. $users[$user->login] = $user;
  537. foreach(UserFirmRank::staticQuery("SELECT *, ufr.id id, u.id uid, r.label rank, f.label firm
  538. FROM {{table}} ufr
  539. LEFT JOIN ".User::tableName()." u ON ufr.user=u.login
  540. LEFT JOIN ".Rank::tableName()." r ON r.id=ufr.rank
  541. LEFT JOIN ".Firm::tableName()." f ON f.id=ufr.firm
  542. WHERE ufr.firm IN (".str_repeat('?,', count($firms) - 1) . '?'.")",$firms,false) as $userFirmRank){
  543. if(empty($myUser->superadmin) && !empty($userFirmRank['superadmin'])) continue;
  544. $user = isset($users[$userFirmRank['user']]) ? $users[$userFirmRank['user']] : new User();
  545. // Petit trick pour l'affichage mustache
  546. $userFirmRank['superadmin'] = !empty($userFirmRank['superadmin']);
  547. $userFirmRank['avatar'] = $user->getAvatar();
  548. $userFirmRank['password'] = '';
  549. $user->name = $user->lastname();
  550. $user->firstname = $user->firstname();
  551. $userFirmRank['user'] = $user;
  552. $response['rows'][] = $userFirmRank;
  553. }
  554. });
  555. Action::register('save_userfirmrank',function(&$response){
  556. global $myUser,$_;
  557. User::check_access('rank','edit');
  558. if(!isset($_['firm'])) throw new Exception('Champ "Établissement" obligatoire');
  559. if(!isset($_['user']) || empty($_['user'])) throw new Exception('Champ "Utilisateur" obligatoire');
  560. if(!isset($_['rank']) || empty($_['rank'])) throw new Exception('Champ "Rang" obligatoire');
  561. foreach(Firm::loadAll() as $firm){
  562. if($_['firm'] != 0 && $_['firm'] != $firm->id) continue;
  563. $user = User::byLogin(stripslashes($_['user']));
  564. $rank = Rank::getById($_['rank']);
  565. if($user->origin == 'active_directory' && (!array_key_exists($firm->id, $user->firms) || !$firm->has_plugin('fr.core.activedirectory'))) continue;
  566. $userFirmRank = UserFirmRank::provide();
  567. $exist = is_null($userFirmRank->id) || $_['firm'] == 0 ? UserFirmRank::rowCount(array('user'=>$user->login,'firm'=>$firm->id,'rank'=>$_['rank'])) : UserFirmRank::rowCount(array('id:!='=>$userFirmRank->id,'user'=>$user->login,'firm'=>$firm->id,'rank'=>$_['rank']));
  568. if($exist > 0){
  569. $response['warning'][] = "Le rang ".$rank->label." est déja défini pour ".$user->fullName()." sur l'établissement ".$firm->label;
  570. continue;
  571. }
  572. $userFirmRank->fromArray($_);
  573. $userFirmRank->firm = $firm->id;
  574. $userFirmRank->user = $user->login;
  575. $userFirmRank->save();
  576. $response['success'][] = "Rang ".$rank->label." ajouté pour ".$user->fullName()." sur l'établissement ".$firm->label;
  577. }
  578. });
  579. Action::register('edit_userfirmrank',function(&$response){
  580. global $myUser,$_;
  581. User::check_access('rank','edit');
  582. $userFirmRank = UserFirmRank::getById($_['id']);
  583. $response = $userFirmRank;
  584. });
  585. Action::register('delete_userfirmrank',function(&$response){
  586. global $myUser,$_,$conf;
  587. User::check_access('rank','delete');
  588. $userFirmRank = UserFirmRank::provide();
  589. $user = User::byLogin($userFirmRank->user);
  590. if($user->preference('default_firm') == $userFirmRank->firm)
  591. UserPreference::delete(array('user'=>$user->login, 'key'=>'default_firm'));
  592. UserFirmRank::deleteById($_['id']);
  593. });
  594. /** UTILISATEURS **/
  595. Action::register('search_user',function(&$response){
  596. global $myUser,$_;
  597. User::check_access('user','read');
  598. foreach(User::getAll(array('right'=>false,'force'=> true)) as $user){
  599. if($user->state == User::INACTIVE || (!$myUser->superadmin && $user->superadmin)) continue;
  600. $user->login = htmlspecialchars_decode($user->login);
  601. $user->name = $user->lastname();
  602. $user->firstname = $user->firstname();
  603. $user->avatar = $user->getAvatar();
  604. $user->formatedLogin = urlencode($user->login);
  605. $response['rows'][] = $user;
  606. }
  607. });
  608. Action::register('user_autocomplete',function(&$response){
  609. global $myUser,$_,$myFirm;
  610. if(!$myUser->can('user','read')) throw new Exception("Vous n'avez pas acces aux utilisateurs");
  611. $response['rows'] = array();
  612. $scope = isset($_['data']['scope']) ? $_['data']['scope'] : $myFirm->id;
  613. if($_['keyword'] == '') return;
  614. if(in_array('user', $_['data']['types'])){
  615. foreach(User::getAll(array('right'=>true) ) as $user){
  616. if($scope!= 0 && !isset($user->firms[$scope])) continue;
  617. if(preg_match('|'.preg_quote(slugify($_['keyword'])).'|i', slugify($user->fullName())) || preg_match('|'.preg_quote(slugify($_['keyword'])).'|i', slugify($user->login))){
  618. $response['rows'][] = array(
  619. 'fullname'=>html_decode_utf8($user->fullName()),
  620. 'name'=>$user->fullName(),
  621. 'uid'=>html_decode_utf8(addslashes($user->login)),
  622. 'id'=>$user->login,
  623. 'mail'=>$user->mail,
  624. 'type'=>'user',
  625. 'avatar'=>$user->getAvatar(),
  626. 'function'=>$user->function
  627. );
  628. }
  629. }
  630. }
  631. if(in_array('rank', $_['data']['types'])){
  632. foreach(Rank::staticQuery('SELECT * FROM {{table}} WHERE label LIKE ?',array('%'.$_['keyword'].'%'),true) as $rank){
  633. $response['rows'][] = array(
  634. 'fullname'=>html_decode_utf8($rank->label),
  635. 'name'=>$rank->label,
  636. 'uid'=>$rank->id,
  637. 'id'=>$rank->id,
  638. 'type'=>'rank',
  639. 'description'=>$rank->description,
  640. );
  641. }
  642. }
  643. });
  644. Action::register('user_by_uid',function(&$response){
  645. global $myUser,$_;
  646. if(!$myUser->can('user','read')) throw new Exception("Vous n'avez pas acces aux utilisateurs");
  647. $response['users'] = array();
  648. $ranks = array();
  649. $users = array();
  650. foreach($_['uids'] as $uid){
  651. if(is_numeric($uid)){
  652. $ranks[] = $uid;
  653. continue;
  654. }
  655. //user
  656. $item = User::byLogin($uid);
  657. if(!$item->login) {
  658. $item->login = $uid;
  659. $item->fullName = $uid;
  660. $item->uid = $uid;
  661. }
  662. $row = $item->toArray();
  663. $row['fullname'] = html_decode_utf8($item->fullName());
  664. $row['name'] = $item->fullName();
  665. $row['uid'] = html_decode_utf8(addslashes($item->login));
  666. $row['id'] = $item->login;
  667. $row['type'] = 'user';
  668. unset($row['password']);
  669. unset($row['token']);
  670. $response['users'][$item->login] = $row;
  671. }
  672. //rank
  673. foreach(Rank::loadAll(array('id:IN'=>implode(',',$ranks))) as $item){
  674. $row = $item->toArray();
  675. $row['fullname'] = $item->label;
  676. $row['name'] = $item->label;
  677. $row['uid'] = $item->id;
  678. $row['id'] = $item->id;
  679. $row['type'] = 'rank';
  680. $response['users'][$item->id] = $row;
  681. }
  682. });
  683. Action::register('account_lost_password',function(&$response){
  684. global $myUser,$myFirm,$_,$conf;
  685. if(!isset($_['mail']) || empty($_['mail']) || !check_mail(trim($_['mail']))) throw new Exception("Adresse e-mail non spécifiée ou incorrecte");
  686. foreach(User::getAll(array('right'=>false) ) as $user){
  687. if(mb_strtolower($user->mail) != mb_strtolower(trim($_['mail']))) continue;
  688. $token = sha1(time().mt_rand(0,1000));
  689. $linkToken = base64_encode($user->login.'::'.$token.'::1');
  690. UserPreference::delete(array('user'=>$user->login,'key'=>'lost_password'));
  691. $saved = new UserPreference();
  692. $saved->user = $user->login;
  693. $saved->key = 'lost_password';
  694. $saved->value = $token;
  695. $saved->save();
  696. $mail = new Mail;
  697. $mail->expeditor = !empty($conf->get('password_lost_expeditor'))?$conf->get('password_lost_expeditor'):"";
  698. $mail->title = "Récupération de mot de passe oublié";
  699. $data = array(
  700. 'link' => ROOT_URL.'/account.lost.php?token='.$linkToken,
  701. 'url' => ROOT_URL,
  702. 'firstname' => $user->firstname,
  703. );
  704. if(!empty($conf->get('password_lost_firm')) && $firm = Firm::getById($conf->get('password_lost_firm'))){
  705. $mail->firm = utf8_decode($firm->label);
  706. $data['firm'] = $firm->label;
  707. $data['logo'] = ROOT_URL.'/'.$firm->logo('url');
  708. }
  709. if(!empty($conf->get('password_lost_mail_expire'))){
  710. $expDays = intval($conf->get('password_lost_mail_expire'));
  711. $data['expDays'] = $expDays;
  712. $data['expDaysPlural'] = $expDays>1?"s":"";
  713. $data['expDate'] = !empty($expDays) ? date("d/m/Y à H:i", strtotime($expDays." days")) : '';
  714. }
  715. $mail->template(__DIR__.SLASH.'mail.reset.password.html',$data,true);
  716. $mail->recipients['to'][] = $user->mail;
  717. $mail->send();
  718. Log::put("Demande de récupération de mot de passe : ".$user->toText(),'Utilisateur');
  719. return;
  720. }
  721. throw new Exception("Aucun compte ne correspond, veuillez contacter un administrateur");
  722. });
  723. Action::register('account_api_save',function(&$response){
  724. global $myUser,$myFirm,$_,$conf;
  725. User::check_access('account','edit');
  726. $myUser->preference('api_enabled',$_['api-enabled']);
  727. $myUser->loadPreferences();
  728. $_SESSION['currentUser'] = serialize($myUser);
  729. });
  730. Action::register('account_save',function(&$response){
  731. global $myUser,$myFirm,$_,$conf;
  732. User::check_access('account','edit');
  733. if(!isset($_['login']) || empty($_['login'])) throw new Exception("Identifiant obligatoire");
  734. if(preg_match('|[,'.preg_quote(htmlspecialchars_decode($conf->get('login_forbidden_char'))).']|i', htmlspecialchars_decode($_['login']), $match)) throw new Exception("Caractère ".$match[0]." interdit dans l'identifiant");
  735. if(!isset($_['mail']) || empty($_['mail'])) throw new Exception('Adresse mail obligatoire');
  736. $_['mail'] = mb_strtolower(trim($_['mail']));
  737. $_['login'] = mb_strtolower(trim($_['login']));
  738. $userForm = new User();
  739. $userForm->fromArray($_);
  740. if(empty($userForm->login) && (!isset($_['password']) || empty($_['password']))) throw new Exception("Mot de passe obligatoire");
  741. //Vérifications & formattage des données
  742. $userForm->firstname = mb_ucfirst(mb_strtolower($userForm->firstname));
  743. $userForm->name = mb_strtoupper($userForm->name);
  744. if(!empty($userForm->mail) && !check_mail($userForm->mail)) throw new Exception('Le format du champ "Mail" est invalide');
  745. if(!empty($userForm->phone) && !check_phone_number($userForm->phone)) throw new Exception('Le format du champ "Téléphone fixe" est invalide');
  746. $userForm->phone = !empty($userForm->phone) ? normalize_phone_number($userForm->phone) : '';
  747. if(!empty($userForm->mobile) && !check_phone_number($userForm->mobile)) throw new Exception('Le format du champ "Téléphone mobile" est invalide');
  748. $userForm->mobile = !empty($userForm->mobile) ? normalize_phone_number($userForm->mobile) : '';
  749. if(!empty($conf->get('password_forbidden_char')) && preg_match('|['.preg_quote(htmlspecialchars_decode($conf->get('password_forbidden_char'))).']|i', htmlspecialchars_decode($_['password']), $match)) throw new Exception("Caractère ".$match[0]." interdit dans le mot de passe");
  750. if($_['password'] != $_['password2']) throw new Exception("Mot de passe et confirmation non similaires");
  751. //Recuperation des hash des precedents passwords
  752. $chain = explode('-',$myUser->preference('account_chain'));
  753. if(!empty(trim($_['password']))) {
  754. $hashedPassword = User::password_encrypt('$a1u7'.$_['password'].'$y$1');
  755. if(in_array($hashedPassword, $chain) && !$myUser->superadmin) throw new Exception("Vous devez choisir un mot de passe différent des précédents");
  756. if(count($chain)==10) array_shift($chain);
  757. $chain[] = $hashedPassword;
  758. $myUser->preference('account_chain',implode('-',$chain));
  759. }
  760. //save des comptes type db
  761. if($myUser->origin == ''){
  762. if(!empty(trim($_['password']))){
  763. $passwordErrors = User::check_password_format($_['password']);
  764. 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));
  765. if(($_['password']==$myUser->login || $_['password']==$myUser->mail) && !$myUser->superadmin) throw new Exception("Le mot de passe ne peut pas être identique à l'identifiant ou à l'e-mail");
  766. $myUser->password = User::password_encrypt($_['password']);
  767. $myUser->preference('passwordTime',time());
  768. }
  769. $myUser->firstname = $userForm->firstname;
  770. $myUser->name = $userForm->name;
  771. $myUser->mail = $userForm->mail;
  772. $myUser->function = $userForm->function;
  773. $myUser->phone = $userForm->phone;
  774. $myUser->mobile = $userForm->mobile;
  775. $myUser->manager = is_object($myUser->manager) ? $myUser->manager->login : $myUser->manager;
  776. if(is_array($myUser->meta)) $myUser->meta = json_encode($myUser->meta);
  777. $myUser->save();
  778. if($myUser->superadmin == 1){
  779. foreach(Firm::loadAll() as $firm)
  780. $firms[$firm->id] = $firm;
  781. $myUser->setFirms($firms);
  782. }
  783. }
  784. //Save de l'avatar
  785. if(!empty($_FILES['avatar']) && $_FILES['avatar']['size']!=0 ){
  786. $login = User::format_avatar_name($myUser->login);
  787. foreach (glob(__ROOT__.FILE_PATH.AVATAR_PATH.$login.".*") as $filename)
  788. unlink($filename);
  789. $avatar = File::upload('avatar',AVATAR_PATH.$login.'.{{ext}}',104857060,array('jpg','png','jpeg','gif'));
  790. Image::resize($avatar['absolute'],150,150);
  791. }
  792. //save des comptes types plugin
  793. Plugin::callHook("user_save",array(&$myUser,$userForm,&$response));
  794. $myUser->loadRights();
  795. if(isset($_SESSION['users_rights'])) unset($_SESSION['users_rights']);
  796. if(isset($_SESSION['users_norights'])) unset($_SESSION['users_norights']);
  797. $_SESSION['currentUser'] = serialize($myUser);
  798. });
  799. Action::register('account_avatar_download',function(&$response){
  800. global $myUser,$_;
  801. User::check_access('profile','read');
  802. try {
  803. $user = str_replace(array('..','/'),'',$_['user']);
  804. $extension = str_replace(array('..','/'),'',$_['extension']);
  805. File::downloadFile(File::dir().AVATAR_PATH.User::format_avatar_name($user).'.'.$extension);
  806. } catch(Exception $e) {
  807. File::downloadFile('img/default-avatar.png');
  808. }
  809. });
  810. Action::register('account_avatar_delete',function(&$response){
  811. global $myUser,$_;
  812. if(!$user = User::byLogin($_['login'])) throw new Exception("Utilisateur inconnu");
  813. if($myUser->login!=$user->login && !$myUser->can('user', 'edit')) throw new Exception("Permissions insuffisantes",403);
  814. foreach(glob(__ROOT__.FILE_PATH.AVATAR_PATH.User::format_avatar_name($user->login).".*") as $filename)
  815. unlink($filename);
  816. if(!file_exists(__ROOT__.FILE_PATH.AVATAR_PATH.'.thumbnails')) return;
  817. foreach(glob(__ROOT__.FILE_PATH.AVATAR_PATH.'.thumbnails'.SLASH.User::format_avatar_name($user->login).".*") as $filename)
  818. unlink($filename);
  819. });
  820. Action::register('save_user',function(&$response){
  821. global $myUser,$_,$conf;
  822. User::check_access('user','edit');
  823. if(!isset($_['login']) || empty($_['login'])) throw new Exception("Identifiant obligatoire");
  824. if(preg_match('|[,'.preg_quote(htmlspecialchars_decode($conf->get('login_forbidden_char'))).']|i', htmlspecialchars_decode($_['login']), $match)) throw new Exception("Caractère ".$match[0]." interdit dans l'identifiant");
  825. //Calcule de la taille max du login en focntion du chemin absolu pour avatar + extension (5)
  826. $osElementMaxLength = OS_path_max_length() - strlen(__ROOT__.FILE_PATH.AVATAR_PATH) - strlen(User::get_avatar_extension_brace());
  827. if(strlen($_['login']) > $osElementMaxLength) throw new Exception("Identifiant trop long : maximum ".$osElementMaxLength." caractères");
  828. $osElementMaxLength = OS_element_max_length();
  829. if(strlen($_['login']) > $osElementMaxLength) throw new Exception("Identifiant trop long : maximum ".$osElementMaxLength." caractères");
  830. if(!isset($_['mail']) || empty($_['mail'])) throw new Exception('Le champ "Mail" est obligatoire');
  831. if(!check_mail($_['mail'])) throw new Exception('Le format du champ "Mail" est invalide');
  832. if(!empty($conf->get('password_forbidden_char')) && preg_match('|['.preg_quote(htmlspecialchars_decode($conf->get('password_forbidden_char'))).']|i', htmlspecialchars_decode($_['password']), $match)) throw new Exception("Caractère ".$match[0]." interdit dans le mot de passe");
  833. if($_['password'] != $_['password2']) throw new Exception("Mot de passe et confirmation non similaires");
  834. $_['mail'] = mb_strtolower(trim($_['mail']));
  835. $_['login'] = trim($_['login']);
  836. $user = User::byLogin($_['login']);
  837. $user = $user && empty($user->origin) ? $user : new User();
  838. //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)
  839. if(empty($user->id)){
  840. $tryExisting = User::byLogin($_['login']);
  841. if($tryExisting && $tryExisting->state=='published')
  842. throw new Exception("Un utilisateur existe déjà avec cet identifiant");
  843. }
  844. if(!$user->login) $user->login = $_['login'];
  845. foreach(User::getAll(array('right'=>false)) as $existingUser)
  846. if($existingUser->mail == $_['mail'] && $existingUser->login != $user->login) throw new Exception("Un utilisateur existe déjà avec cette adresse e-mail");
  847. if($user->id == 0 && (!isset($_['password']) || empty($_['password']))) throw new Exception("Mot de passe obligatoire");
  848. if(!empty(trim($_['password']))){
  849. $passwordErrors = User::check_password_format(html_entity_decode($_['password']));
  850. 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));
  851. if($_['password']==$_['login'] || $_['password']==$_['mail'] ) throw new Exception("Le mot de passe ne peut pas être identique à l'identifiant ou à l'e-mail");
  852. $user->password = User::password_encrypt(html_entity_decode($_['password']));
  853. $user->preference('passwordTime',time());
  854. }
  855. $user->firstname = mb_ucfirst(mb_strtolower($_['firstname']));
  856. $user->name = mb_strtoupper($_['name']);
  857. $user->mail = $_['mail'];
  858. $user->state = User::ACTIVE;
  859. if(isset($_['manager'])) $user->manager = $_['manager'];
  860. if(is_array($user->meta)) $user->meta = json_encode($user->meta);
  861. $user->save();
  862. if(isset($_SESSION['users_rights'])) unset($_SESSION['users_rights']);
  863. if(isset($_SESSION['users_norights'])) unset($_SESSION['users_norights']);
  864. $user->password = '';
  865. Log::put("Création/Modification de l'utilisateur ".$user->login,'Utilisateur');
  866. });
  867. Action::register('edit_user',function(&$response){
  868. global $myUser,$_;
  869. User::check_access('user','edit');
  870. $user = User::byLogin($_['login'], true, true);
  871. $user->login = htmlspecialchars_decode($user->login);
  872. $user->name = $user->lastname();
  873. $user->firstname = $user->firstname();
  874. if(!$user) throw new Exception("Utilisateur non identifié");
  875. $user->password = '';
  876. $response = $user;
  877. });
  878. Action::register('delete_user',function(&$response){
  879. global $myUser,$_;
  880. User::check_access('user','delete');
  881. $user = User::byLogin($_['login'], true, true);
  882. if(!$user) throw new Exception("Utilisateur non identifié");
  883. $user->loadRanks();
  884. if($user->superadmin == 1) throw new Exception("Vous ne pouvez pas supprimer le compte Super Admin");
  885. if($user->login == $myUser->login) throw new Exception("Vous ne pouvez pas supprimer votre propre compte");
  886. if(!$user = User::getById($user->id)) throw new Exception("Impossible de supprimer un compte en dehors de de la base de données");
  887. $user->state = User::INACTIVE;
  888. $user->save();
  889. foreach(UserFirmRank::loadAll(array('user'=>$user->login)) as $ufrLink)
  890. UserFirmRank::deleteById($ufrLink->id);
  891. if(isset($_SESSION['users_rights'])) unset($_SESSION['users_rights']);
  892. if(isset($_SESSION['users_norights'])) unset($_SESSION['users_norights']);
  893. Log::put("Suppression de l'utilisateur ".$user->toText(),'Utilisateur');
  894. });
  895. /** DROITS **/
  896. Action::register('core_right_search',function(&$response){
  897. global $myUser,$_;
  898. if(!$myUser->connected()) return $response;
  899. foreach(Right::loadAll(array('scope'=>$_['scope'],'uid'=>$_['uid'],'firm:IN'=>array($_['firm'],'NULL') )) as $right){
  900. $row = $right->toArray();
  901. if(!$right->read) unset($row['read']);
  902. if(!$right->edit) unset($row['edit']);
  903. if(!$right->delete) unset($row['delete']);
  904. if(!$right->configure) unset($row['configure']);
  905. if(!$right->recursive) unset($row['recursive']);
  906. if($row['firm']=='0') unset($row['firm']);
  907. if($right->targetScope == 'rank'){
  908. $row['target'] = '<i class="far fa-address-card"></i> '.Rank::getById($right->targetUid)->label;
  909. }else{
  910. $user = User::byLogin($right->targetUid);
  911. $row['target'] = '<img class="avatar avatar-mini avatar-rounded" src="'.$user->getAvatar().'"> '.$user->fullName();
  912. }
  913. $response['rows'][] = $row;
  914. }
  915. });
  916. //Récuperation ou edition d'élément right
  917. Action::register('core_right_save',function(&$response){
  918. global $myUser,$_;
  919. $right = new Right();
  920. $right->fromArray($_);
  921. $scopes = Right::availables('scope');
  922. if(!isset($scopes[$right->scope]) ||!isset($scopes[$right->scope]['check'])) throw new Exception("Aucun control d'accès n'a été défini sur cette section");
  923. if(!$myUser->superadmin){ //todo décommenter
  924. $check = $scopes[$right->scope]['check'];
  925. $check('save',$right);
  926. }
  927. $right->save();
  928. });
  929. Action::register('core_right_delete',function(&$response){
  930. global $myUser,$_;
  931. $right = Right::getById($_['id']);
  932. $scopes = Right::availables('scope');
  933. if(!isset($scopes[$right->scope]) ||!isset($scopes[$right->scope]['check'])) throw new Exception("Aucun control d'accès n'a été défini sur cette section");
  934. if(!$myUser->superadmin){ //todo décommenter
  935. $check = $scopes[$right->scope]['check'];
  936. $check('delete',$right);
  937. }
  938. Right::deleteById($_['id']);
  939. });
  940. //////////////////////
  941. Action::register('search_right',function(&$response){
  942. global $myUser,$_;
  943. User::check_access('rank','edit');
  944. if(!isset($_['firm'])) throw new Exception("Etablissement non spécifié");
  945. $wholeRights = array();
  946. $scopes = array();
  947. $scopes = Right::availables('scope');
  948. $firms = Firm::loadAll();
  949. $firms[] = Firm::anonymous_firm();
  950. foreach($firms as $firm){
  951. if($firm->id != $_['firm'] && $_['firm'] != '0') continue;
  952. $rights = Right::loadAll(array('targetUid'=>$_['targetUid'],'firm'=>$firm->id));
  953. $rightsTable = array();
  954. foreach($rights as $right)
  955. $rightsTable[$right->scope] = $right;
  956. if($_['firm'] == '0'){
  957. foreach($scopes as $scope=>$options) {
  958. $right = isset($rightsTable[$scope])? $rightsTable[$scope] : new Right();
  959. $wholeRights[$scope]['read'][$firm->id] = (int)$right->read;
  960. $wholeRights[$scope]['edit'][$firm->id] = (int)$right->edit;
  961. $wholeRights[$scope]['delete'][$firm->id] = (int)$right->delete;
  962. $wholeRights[$scope]['configure'][$firm->id] = (int)$right->configure;
  963. }
  964. }
  965. }
  966. foreach ($scopes as $scope=>$options) {
  967. if(!$options['global']) continue;
  968. if($_['firm'] == '0'){
  969. $read = count(array_unique($wholeRights[$scope]['read'])) === 1 ? end($wholeRights[$scope]['read']) : 2;
  970. $edit = count(array_unique($wholeRights[$scope]['edit'])) === 1 ? end($wholeRights[$scope]['edit']) : 2;
  971. $delete = count(array_unique($wholeRights[$scope]['delete'])) === 1 ? end($wholeRights[$scope]['delete']) : 2;
  972. $configure = count(array_unique($wholeRights[$scope]['configure'])) === 1 ? end($wholeRights[$scope]['configure']) : 2;
  973. }else{
  974. $right = isset($rightsTable[$scope])? $rightsTable[$scope] : new Right();
  975. $read = $right->read;
  976. $edit = $right->edit;
  977. $delete = $right->delete;
  978. $configure = $right->configure;
  979. }
  980. $response['rows'][] = array(
  981. 'scope'=>$scope,
  982. 'description'=>$options['label'],
  983. 'read'=>(int)$read,
  984. 'edit'=>(int)$edit,
  985. 'delete'=>(int)$delete,
  986. 'configure'=>(int)$configure
  987. );
  988. usort($response['rows'], function($a, $b){
  989. return strcmp($a['scope'], $b['scope']);
  990. });
  991. }
  992. });
  993. Action::register('toggle_right',function(&$response){
  994. global $myUser,$_,$myFirm;
  995. User::check_access('rank','edit');
  996. if(!isset($_['scope']) || empty($_['scope'])) throw new Exception("Scope non spécifié");
  997. if(!isset($_['targetUid']) || empty($_['targetUid'])) throw new Exception("target Uid non spécifié");
  998. if(!isset($_['right']) || empty($_['right'])) throw new Exception("Droit non spécifié");
  999. if(!isset($_['firm'])) throw new Exception("Établissement non spécifié");
  1000. $firms = Firm::loadAll();
  1001. $firms[] = Firm::anonymous_firm();
  1002. foreach($firms as $firm){
  1003. if($firm->id != $_['firm'] && $_['firm'] != '0') continue;
  1004. $item = Right::load(array('targetUid'=>$_['targetUid'],'firm'=>$firm->id,'scope'=>$_['scope']));
  1005. $item = !$item ? new Right() : $item ;
  1006. $item->targetUid = $_['targetUid'];
  1007. $item->firm = $firm->id;
  1008. $item->targetScope = 'rank';
  1009. $item->scope = $_['scope'];
  1010. $item->{$_['right']} = $_['state'];
  1011. $item->save();
  1012. $myUser->loadRights();
  1013. $_SESSION['currentUser'] = serialize($myUser);
  1014. }
  1015. });
  1016. /** RANGS **/
  1017. Action::register('search_rank',function(&$response){
  1018. global $myUser,$_;
  1019. User::check_access('rank','read');
  1020. $rankQry = 'SELECT *,(SELECT GROUP_CONCAT(CONCAT(f.label,":",`scope`,":",`read`,":",`edit`,":",`delete`,":",`configure`))
  1021. FROM `'.Right::tableName().'` r LEFT JOIN firm f ON f.id = r.firm
  1022. WHERE (r.read=? OR r.edit=? OR r.delete=? OR r.configure=?) AND r.targetUid={{table}}.id) as rights
  1023. FROM {{table}}';
  1024. $ranks = Rank::staticQuery($rankQry,array(1,1,1,1),true);
  1025. foreach($ranks as $rank){
  1026. $row = $rank->toArray(true);
  1027. //Gestion des rights sur les rangs "coeur" ayant des perms
  1028. $row['read'] = $row['edit'] = $row['delete'] = $row['configure'] = true;
  1029. if($rights = Right::loadAll(array('scope'=>'rank', 'uid'=>$rank->id))){
  1030. if(!$myUser->can('rank','read',$rank->id)) continue;
  1031. $row['edit'] = $myUser->can('rank','edit',$rank->id);
  1032. $row['delete'] = $myUser->can('rank','delete',$rank->id);
  1033. $row['configure'] = $myUser->can('rank','configure',$rank->id);
  1034. }
  1035. $row['rights'] = array();
  1036. foreach (explode(',', $rank->foreign('rights')) as $right) {
  1037. $infos = explode(':', $right);
  1038. $row['rights'][] = array(
  1039. 'configure' => !empty(array_pop($infos)),
  1040. 'delete' => !empty(array_pop($infos)),
  1041. 'edit' => !empty(array_pop($infos)),
  1042. 'read' => !empty(array_pop($infos)),
  1043. 'scope' => array_pop($infos),
  1044. 'firm' => array_pop($infos)
  1045. );
  1046. usort($row['rights'], function($a, $b){
  1047. return strcmp($a['firm'], $b['firm']);
  1048. });
  1049. }
  1050. $response['rows'][] = $row;
  1051. }
  1052. });
  1053. Action::register('save_rank',function(&$response){
  1054. global $myUser,$_;
  1055. User::check_access('rank','edit');
  1056. if(!isset($_['label']) || empty($_['label'])) throw new Exception("Libellé obligatoire");
  1057. $item = isset($_['id']) && !empty($_['id']) ? Rank::getById($_['id']) : new Rank();
  1058. $item->label = $_['label'];
  1059. $item->description = $_['description'];
  1060. $item->save();
  1061. Log::put("Ajout/Modification du rang ".$item->toText(),'Rang');
  1062. });
  1063. Action::register('edit_rank',function(&$response){
  1064. global $myUser,$_;
  1065. User::check_access('rank','edit');
  1066. $response = Rank::getById($_['id']);
  1067. });
  1068. Action::register('delete_rank',function(&$response){
  1069. global $myUser,$_;
  1070. User::check_access('rank','delete');
  1071. $rank = Rank::getById($_['id']);
  1072. Rank::deleteById($_['id']);
  1073. Log::put("Suppression du rang ".$rank->toText(),'Rang');
  1074. });
  1075. /** LISTES **/
  1076. Action::register('search_dictionnary',function(&$response){
  1077. global $myUser,$_;
  1078. User::check_access('dictionnary','read');
  1079. $parent = '';
  1080. if(!empty($_['parent']) && is_numeric($_['parent']))
  1081. $parent = $_['parent'];
  1082. foreach(Dictionnary::loadAll(array('parent'=>$parent, 'state'=>Dictionnary::ACTIVE), array(' label ASC ')) as $item){
  1083. $item->label = html_entity_decode($item->label);
  1084. $response['rows'][] = $item->toArray();
  1085. }
  1086. });
  1087. Action::register('save_dictionnary',function(&$response){
  1088. global $myUser,$_;
  1089. User::check_access('dictionnary','edit');
  1090. if(!isset($_['label']) || empty(trim($_['label']))) throw new Exception("Libellé obligatoire");
  1091. if(!is_numeric($_['parent'])){
  1092. if($myUser->can('dictionnary','configure'))
  1093. $_['parent'] = 0;
  1094. else
  1095. throw new Exception("Veuillez sélectionner une liste");
  1096. }
  1097. $item = Dictionnary::provide();
  1098. $item->label = trim($_['label']);
  1099. $item->parent = $_['parent'];
  1100. $item->state = Dictionnary::ACTIVE;
  1101. if(!empty($_['slug'])){
  1102. $parameters = array('slug'=>$_['slug'], 'state'=>Dictionnary::ACTIVE);
  1103. if(isset($item->id) && !empty($item->id)) $parameters['id:!='] = $item->id;
  1104. if(Dictionnary::rowCount($parameters)>0) throw new Exception("Le slug renseigné est déjà utilisé");
  1105. $item->slug = $_['slug'];
  1106. }
  1107. if(empty($item->slug)){
  1108. $parentSlug = $_['parent'] == 0 ? '' : Dictionnary::getById($_['parent'])->slug;
  1109. $slug = empty($parentSlug) ? $_['label'] : $parentSlug.'-'.$_['label'];
  1110. $item->slug = generateSlug($slug, Dictionnary::class, 'slug', '', '_');
  1111. }
  1112. if(isset($_['sublistlabel'])) $item->sublistlabel = $_['sublistlabel'];
  1113. $item->save();
  1114. Log::put("Création/Modification de l'item de liste ".$item->toText(),'Liste');
  1115. });
  1116. Action::register('edit_dictionnary',function(&$response){
  1117. global $myUser,$_;
  1118. User::check_access('dictionnary','edit');
  1119. $dictionnary = Dictionnary::getById($_['id']);
  1120. $response = $dictionnary->toArray(true);
  1121. });
  1122. Action::register('delete_dictionnary',function(&$response){
  1123. global $myUser,$_;
  1124. User::check_access('dictionnary','delete');
  1125. if(!isset($_['id']) || empty($_['id'])) throw new Exception("Aucun identifiant spécifié");
  1126. $item = Dictionnary::getById($_['id']);
  1127. $item->state = Dictionnary::INACTIVE;
  1128. $item->save();
  1129. Dictionnary::change(array('state'=>Dictionnary::INACTIVE), array('parent'=>$item->id));
  1130. Log::put("Suppression de la liste et des sous-listes associées".$item->toText(), 'Liste');
  1131. });
  1132. Action::register('get_parent_dictionnary',function(&$response){
  1133. global $myUser,$_;
  1134. if(!$myUser->connected()) throw new Exception("permission denied");
  1135. $selected = Dictionnary::loadAll(array("id"=>$_['selected']));
  1136. foreach ($selected as $item) {
  1137. if($item->parent == 0) {
  1138. $parents = Dictionnary::loadAll(array("parent"=>$item->parent), array(' label ASC '));
  1139. } else {
  1140. $tmpParent = Dictionnary::loadAll(array("id"=>$item->parent), array(' label ASC '));
  1141. $parents = Dictionnary::loadAll(array("parent"=>$tmpParent[0]->parent), array(' label ASC '));
  1142. }
  1143. $parentId = !empty($tmpParent) ? $tmpParent[0]->id : '';
  1144. $response['rows'][] = array(
  1145. 'parents'=> $parents,
  1146. 'currentId'=> $item->id,
  1147. 'parentId'=> $parentId,
  1148. 'label'=> $item->label
  1149. );
  1150. }
  1151. });
  1152. Action::register('load_dictionnary_component',function(&$response){
  1153. global $myUser,$_;
  1154. //double check afin de laisse la possiubilité aux non connectés de voir les listes sur certains projets
  1155. if(!$myUser->connected() && !$myUser->can('dictionnary','read')){
  1156. $response['content'] = array();
  1157. return;
  1158. }
  1159. $dictionnaries = array();
  1160. if(isset($_['slug']) && $_['slug'] != ""){
  1161. $dictionnaries = Dictionnary::load(array("slug"=>$_['slug']));
  1162. }else{
  1163. $dictionnaries = new Dictionnary();
  1164. $dictionnaries->id = 0;
  1165. }
  1166. if(isset($_['parentId']) && $_['parentId'] != ""){
  1167. $dictionnaries = Dictionnary::getById($_['parentId']);
  1168. $dictionnaries->id = 0;
  1169. }
  1170. if($dictionnaries) {
  1171. $dictionnaries = $dictionnaries->toArray();
  1172. if(!isset($_['depth'])) $_['depth'] = 1;
  1173. $dictionnaries['childs'] = Dictionnary::childs(array('id'=>$dictionnaries['id']),array('depth'=>$_['depth'],'format'=>'array'));
  1174. }
  1175. if(isset($_['value']) && $_['value'] != "" ){
  1176. $output = is_numeric($_['value']) ? 'id' : 'slug';
  1177. if($output == 'id' && $_['value'] == 0) return $dictionnaries;
  1178. if(!$_['hierarchy'] || (isset($_['slug']) && $_['slug'] == "" )){
  1179. foreach ($dictionnaries['childs'] as $i => $child) {
  1180. if($child[$output] == $_['value']) $child['selected'] = true;
  1181. $dictionnaries['childs'][$i] = $child;
  1182. }
  1183. } else {
  1184. $dictionnaries = Dictionnary::hierarchy($_['value'],$_['slug']);
  1185. }
  1186. }
  1187. $response['content'] = $dictionnaries;
  1188. });
  1189. Action::register('dictionnary_slug_proposal',function(&$response){
  1190. global $myUser,$_;
  1191. if(!$myUser->connected()) throw new Exception("Permission denied");
  1192. if(!isset($_['label']) || empty($_['label'])) return;
  1193. //Check si l'item n'a pas déjà un slug
  1194. if(isset($_['id']) && !empty($_['id']) && is_numeric($_['id'])){
  1195. $item = Dictionnary::provide();
  1196. if(!empty($item->slug)) return;
  1197. }
  1198. $parentSlug = empty($_['parent']) ? '' : Dictionnary::getById($_['parent'])->slug;
  1199. $slug = empty($parentSlug) ? $_['label'] : $parentSlug.'_'.$_['label'];
  1200. $response['slug'] = generateSlug($slug, Dictionnary::class, 'slug', '', '_');
  1201. });
  1202. /* Composant tag list */
  1203. Action::register('tag_list_autocomplete',function(&$response){
  1204. global $myUser,$_;
  1205. if(!$myUser->can('dictionnary','read')) throw new Exception("Vous n'avez pas acces aux listes");
  1206. $response['rows'] = array();
  1207. foreach(Dictionnary::staticQuery('SELECT * FROM {{table}} WHERE parent=(SELECT id from {{table}} WHERE slug= ? LIMIT 1) AND label LIKE ? AND state = ? ',array($_['data']['parent'],'%'.$_['keyword'].'%',Dictionnary::ACTIVE),true) as $item){
  1208. $response['rows'][] = array(
  1209. 'name'=>$item->label,
  1210. 'id'=>$item->id,
  1211. 'slug'=>$item->slug
  1212. );
  1213. }
  1214. });
  1215. Action::register('tag_list_autocreate',function(&$response){
  1216. global $myUser,$_;
  1217. if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
  1218. $response = array();
  1219. $parent = Dictionnary::bySlug($_['slug']);
  1220. $newtag = new Dictionnary();
  1221. $newtag->state = Dictionnary::ACTIVE;
  1222. $newtag->parent= $parent->id;
  1223. $newtag->label= $_['label'];
  1224. $newtag->slug= $parent->slug.'-'.slugify($_['label']);
  1225. $newtag->save();
  1226. $response = array(
  1227. 'name'=>$newtag->label,
  1228. 'id'=>$newtag->id,
  1229. 'slug'=>$newtag->slug
  1230. );
  1231. });
  1232. Action::register('tag_list_by_id',function(&$response){
  1233. global $myUser,$_;
  1234. if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
  1235. $response['tags'] = array();
  1236. $ids = explode(',',$_['id']);
  1237. foreach(Dictionnary::loadAll(array('id:IN'=>$ids)) as $dictionnary){
  1238. $dictionnaryMapping[$dictionnary->id] = $dictionnary;
  1239. }
  1240. foreach ($ids as $id) {
  1241. if(!isset($dictionnaryMapping[$id])) continue;
  1242. $item = $dictionnaryMapping[$id];
  1243. $row = $item->toArray();
  1244. $row['label'] = $item->label;
  1245. $row['slug'] = $item->slug;
  1246. $row['id'] = $item->id;
  1247. $response['tags'][] = $row;
  1248. }
  1249. });
  1250. /** TABLEAU DE DICTIONNARY */
  1251. Action::register('dictionnary_table_search',function(&$response){
  1252. global $myUser,$_;
  1253. if(!$myUser->connected()) throw new Exception("permission denied");
  1254. if(!is_numeric($_['id'])) throw new Exception("Aucun identifiant de liste spécifié");
  1255. $dic = Dictionnary::getById($_['id']);
  1256. $response['dictionnary'] = $dic->toArray(true);
  1257. foreach (Dictionnary::childs(array('slug'=>$dic->slug)) as $child)
  1258. $response['rows'][] = $child->toArray(true);
  1259. });
  1260. Action::register('dictionnary_table_save',function(&$response){
  1261. global $myUser,$_;
  1262. if(!$myUser->connected()) throw new Exception("Permission denied");
  1263. if(!isset($_['label']) || empty($_['label'])) throw new Exception("Aucun libellé de liste renseigné");
  1264. if(!isset($_['id']) && !isset($_['list'])) throw new Exception("Aucun identifiant de liste ou de parent de liste trouvé");
  1265. $dic = isset($_['id']) && !empty($_['id'])? Dictionnary::getById($_['id']) : new Dictionnary();
  1266. $dic->parent = $_['list'];
  1267. $dic->label = $_['label'];
  1268. if(isset($_['slug']) && !empty($_['slug'])) {
  1269. $parameters = array('slug'=>$_['slug'], 'state'=>Dictionnary::ACTIVE);
  1270. if(isset($dic->id) && !empty($dic->id)) $parameters['id:!='] = $dic->id;
  1271. if(Dictionnary::rowCount($parameters)>0) throw new Exception("Le slug renseigné est déjà utilisé");
  1272. $dic->slug = $_['slug'];
  1273. }
  1274. $dic->state = Dictionnary::ACTIVE;
  1275. $dic->save();
  1276. });
  1277. /* COMPOSANT LOCATION */
  1278. Action::register('location_search',function(&$response){
  1279. global $myUser,$_,$conf;
  1280. if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
  1281. $appUrl = $conf->get('maps_api_suggest_url');
  1282. $appId = $conf->get('maps_api_id');
  1283. $appKey = $conf->get('maps_api_key');
  1284. if(empty($appUrl) || empty($appId) || empty($appKey)) throw new Exception("Impossible d'initialiser le composant de localisation");
  1285. if(!isset($_['keyword']) || empty($_['keyword'])) return;
  1286. $default = array(
  1287. 'query' => $_['keyword'],
  1288. 'app_id' => $appId,
  1289. 'app_code' => $appKey
  1290. );
  1291. $params = array_merge($default, $_['data']);
  1292. $curlOpt = array(
  1293. CURLOPT_URL => sprintf("%s?%s", $appUrl, http_build_query($params)),
  1294. CURLOPT_HTTPHEADER => array(
  1295. 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0',
  1296. 'Content-Type: application/json',
  1297. ),
  1298. CURLOPT_RETURNTRANSFER => 1,
  1299. CURLOPT_HTTPAUTH => CURLAUTH_ANY,
  1300. CURLOPT_SSL_VERIFYPEER => false,
  1301. CURLOPT_SSL_VERIFYHOST => false,
  1302. );
  1303. $ch = curl_init();
  1304. curl_setopt_array($ch, $curlOpt);
  1305. $result = curl_exec($ch);
  1306. if($result === false) throw new Exception("Erreur de récupération cURL : ".curl_error($curl));
  1307. $result = json_decode($result);
  1308. $infos = curl_getinfo($ch);
  1309. curl_close($ch);
  1310. $response['rows'] = $result->suggestions;
  1311. });
  1312. Action::register('location_detail_search',function(&$response){
  1313. global $myUser,$_,$conf;
  1314. if(!$myUser->connected()) throw new Exception("Vous devez être connecté",401);
  1315. $appUrl = $conf->get('maps_api_geocode_url');
  1316. $appId = $conf->get('maps_api_id');
  1317. $appKey = $conf->get('maps_api_key');
  1318. if(empty($appUrl) || empty($appId) || empty($appKey)) throw new Exception("Impossible de récupérer les détails de la localisation");
  1319. if(!isset($_['locationId']) || empty($_['locationId'])) return;
  1320. $params = array(
  1321. 'locationid' => $_['locationId'],
  1322. 'app_id' => $appId,
  1323. 'app_code' => $appKey
  1324. );
  1325. $curlOpt = array(
  1326. CURLOPT_URL => sprintf("%s?%s", $appUrl, http_build_query($params)),
  1327. CURLOPT_HTTPHEADER => array(
  1328. 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0',
  1329. 'Content-Type: application/json',
  1330. ),
  1331. CURLOPT_RETURNTRANSFER => 1,
  1332. CURLOPT_HTTPAUTH => CURLAUTH_ANY,
  1333. CURLOPT_SSL_VERIFYPEER => false,
  1334. CURLOPT_SSL_VERIFYHOST => false,
  1335. );
  1336. $ch = curl_init();
  1337. curl_setopt_array($ch, $curlOpt);
  1338. $response = curl_exec($ch);
  1339. if($response === false) throw new Exception("Erreur de récupération cURL : ".curl_error($curl));
  1340. $response = json_decode($response);
  1341. $infos = curl_getinfo($ch);
  1342. curl_close($ch);
  1343. });
  1344. /** CRONTAB */
  1345. Action::register('cron',function(&$response){
  1346. try{
  1347. if(php_sapi_name() !== 'cli') throw new Exception("Le cron ne peut être executé qu'en mode CLI depuis le serveur");
  1348. Plugin::callHook('cron', array(time()));
  1349. }catch(Exception $e){
  1350. file_put_contents(__DIR__.SLASH.'cron.log',date('d-m-Y H:i').' | '.$e->getMessage().PHP_EOL,FILE_APPEND);
  1351. }
  1352. });
  1353. /** FILES & UPLOADS */
  1354. //Gestion de l'upload temporaire (avant soumission d'un form)
  1355. Action::register('upload_temporary_file',function(&$response){
  1356. global $myUser,$_;
  1357. User::check_access('file','edit');
  1358. $response['previews'] = array();
  1359. $fileIndex = isset($_FILES[$_['index']]) ? $_FILES[$_['index']] : $_FILES['document'];
  1360. File::clear_temp();
  1361. for($i=0; $i<count($_FILES[$_['index']]['name']);$i++) {
  1362. $tempPath = File::temp().basename($fileIndex['tmp_name'][$i]);
  1363. move_uploaded_file($fileIndex['tmp_name'][$i], $tempPath);
  1364. $ext = getExt($fileIndex['name'][$i]);
  1365. $response['previews'][] = array(
  1366. 'path' => basename($fileIndex['tmp_name'][$i]),
  1367. 'name' => $fileIndex['name'][$i],
  1368. 'temporary' => true,
  1369. 'ext' => $ext,
  1370. 'url' => 'action.php?action=download_temporary_file&name='.$fileIndex['name'][$i].'&path='.basename($fileIndex['tmp_name'][$i]),
  1371. 'icon' => getExtIcon($ext)
  1372. );
  1373. }
  1374. });
  1375. Action::register('download_temporary_file',function(&$response){
  1376. global $myUser,$_;
  1377. User::check_access('file','read');
  1378. File::downloadFile(File::temp().$_['path'],$_['name']);
  1379. });
  1380. /** GENERAL SETTINGS **/
  1381. Action::register('general_settings_save',function(&$response){
  1382. global $myUser, $_, $conf;
  1383. User::check_access('setting_global','configure');
  1384. $_FILES = normalize_php_files();
  1385. if(isset($_FILES['fields'])) $_FILES = $_FILES['fields'];
  1386. $coreFolder = __ROOT__.FILE_PATH.'core'.SLASH;
  1387. if(!file_exists($coreFolder)) mkdir($coreFolder,0755,true);
  1388. //Ajout logo
  1389. if(!empty($_['logo-light'])){
  1390. $logo = File::save_component('logo-light', 'core/public/logo.{{extension}}');
  1391. Image::resize($logo[0]['absolute'], 200, 200);
  1392. Image::toPng($logo[0]['absolute']);
  1393. unset($_['logo-light']);
  1394. }
  1395. //Ajout logo dark
  1396. if(!empty($_['logo-dark'])){
  1397. $logo = File::save_component('logo-dark', 'core/public/logo.dark.{{extension}}');
  1398. Image::resize($logo[0]['absolute'], 200, 200);
  1399. Image::toPng($logo[0]['absolute']);
  1400. unset($_['logo-dark']);
  1401. }
  1402. //Ajout favicon
  1403. if(!empty($_['favicon'])){
  1404. $logo = File::save_component('favicon', 'core/public/favicon.{{extension}}');
  1405. Image::resize($logo[0]['absolute'], 16, 16);
  1406. Image::toPng($logo[0]['absolute']);
  1407. unset($_['favicon']);
  1408. }
  1409. //Durée de conservation des logs
  1410. foreach(Log::staticQuery('SELECT DISTINCT category FROM {{table}}',array(),true) as $log):
  1411. $slug = slugify($log->category);
  1412. $key = 'log_retention_time_'.$slug;
  1413. if(!isset($_[$key])) continue;
  1414. if($_[$key] == 0 || !is_numeric($_[$key])) $_[$key] = '';
  1415. $conf->put($key,$_[$key]);
  1416. endforeach;
  1417. //Gestion save des configuration générales
  1418. foreach(Configuration::setting('configuration-global') as $key => $value){
  1419. if(!is_array($value)) continue;
  1420. $allowedSettings[] = $key;
  1421. }
  1422. if(isset($_['logout_inactivity_delay']) && !empty($_['logout_inactivity_delay']) && $_['logout_inactivity_delay'] < 60) throw new Exception("Le délai d'inactivité doit être supérieur ou égal à 60");
  1423. foreach($_ as $key => $value)
  1424. if(in_array($key, $allowedSettings)) $conf->put($key, $value);
  1425. //Politique de mot de passes
  1426. if(isset($_['password_format'])) $conf->put('password_format',$_['password_format']);
  1427. //Maintenance
  1428. if(isset($_['maintenance'])){
  1429. if($_['maintenance']){
  1430. if(file_exists('disabled.maintenance')) rename('disabled.maintenance', 'enabled.maintenance');
  1431. file_put_contents('enabled.maintenance', trim($_['maintenance-content']));
  1432. } else {
  1433. if(file_exists('enabled.maintenance')) rename('enabled.maintenance', 'disabled.maintenance');
  1434. file_put_contents('disabled.maintenance', trim($_['maintenance-content']));
  1435. }
  1436. }
  1437. });
  1438. Action::register('general_reset_password_delay',function(&$response){
  1439. global $myUser, $_, $conf;
  1440. User::check_access('setting_global','configure');
  1441. foreach(User::getAll(array('right'=>false)) as $user)
  1442. $user->preference('passwordTime',strtotime('01/01/1990'));
  1443. });
  1444. //Récupération logo application générale
  1445. Action::register('core_setting_logo',function(&$response){
  1446. global $myUser,$_;
  1447. User::check_access('setting_global','configure');
  1448. $variant = '';
  1449. if(!empty($_['data']) && !empty($_['data']['variant'])){
  1450. $variant = $_['data']['variant'];
  1451. $variant = $variant == 'light' ? '' : '.'.$variant;
  1452. }
  1453. File::handle_component(array(
  1454. 'namespace' => 'core', //stockés dans core/*.*
  1455. 'access' => 'setting_global', // crud sur core,
  1456. 'size' => '10000000', // taille max
  1457. 'storage' => 'core/public/logo'.$variant.'.{png,jpg,jpeg,gif}' //chemin complet vers le fichier stocké
  1458. ),$response);
  1459. });
  1460. //Récupération logo application générale
  1461. Action::register('core_setting_favicon',function(&$response){
  1462. global $myUser,$_;
  1463. User::check_access('setting_global','configure');
  1464. File::handle_component(array(
  1465. 'namespace' => 'core', //stockés dans core/*.*
  1466. 'access' => 'setting_global', // crud sur core,
  1467. 'size' => '1000000', // taille max
  1468. 'extension' => 'png', // png uniquement
  1469. 'storage' => 'core/public/favicon.png' //chemin complet vers le fichier stocké
  1470. ),$response);
  1471. });
  1472. //Permet de se connecter "en tant que"
  1473. Action::register('user_impersonation',function(&$response){
  1474. try{
  1475. global $myUser,$myFirm,$_,$conf;
  1476. if(!$myUser->superadmin) throw new Exception("Seul le super administrateur peut exécuter cette fonctionnalité");
  1477. if(!isset($_['login'])) throw new Exception("Identifiant non spécifié");
  1478. if(isset($_SESSION['users_rights'])) unset($_SESSION['users_rights']);
  1479. if(isset($_SESSION['users_norights'])) unset($_SESSION['users_norights']);
  1480. $myUser = User::connectLogin($_['login']);
  1481. Log::put("Impersonation de l'utilisateur : ".$myUser->login,"Utilisateur");
  1482. $_SESSION['currentUser'] = serialize($myUser);
  1483. $_SESSION['firm'] = serialize($myFirm);
  1484. header('location: index.php?info='.rawurlencode('Connecté avec l\'utilisateur : '.$user->login));
  1485. } catch(Exception $e){
  1486. header('location: setting.php?section=user&error='.rawurlencode($e->getMessage()));
  1487. }
  1488. });
  1489. /* HISTORY */
  1490. Action::register('history_search',function(&$response){
  1491. global $myUser,$_;
  1492. User::check_access('history','read');
  1493. $filters = array();
  1494. $response['rows'] = array();
  1495. //Récuperation du nombre de messages importants uniquement
  1496. if(!empty($_['showImportant'])){
  1497. $data = array(History::IMPORTANCE_IMPORTANT);
  1498. $query = 'SELECT scope,uid,COUNT(id) thecount FROM {{table}} WHERE importance=? AND ( ';
  1499. $i=0;
  1500. foreach ($_['scopes'] as $scope=>$values) {
  1501. $marks = array_fill(0, count($values), '?');
  1502. $data[] = $scope;
  1503. $data = array_merge($data,$values);
  1504. $query .= ($i==0 ?'' :' OR ').' (scope = ? AND uid IN('.implode(',',$marks).')) ';
  1505. $i++;
  1506. }
  1507. $query .= ' ) GROUP BY scope,uid ';
  1508. $importants = History::staticQuery($query,$data)->fetchAll();
  1509. //On renvoie 0 s'il n'y a pas de résultat afin d'afficher les notifications de l'historique
  1510. if(empty($importants)){
  1511. foreach($_['scopes'] as $scope=>$values){
  1512. foreach($values as $uid){
  1513. $importants[] = array('scope'=>$scope,'uid'=>$uid,'thecount'=>0);
  1514. }
  1515. }
  1516. }
  1517. foreach($importants as $line)
  1518. $response['rows'][] = array('scope'=>$line['scope'],'uid'=>$line['uid'],'number'=>$line['thecount']);
  1519. //Récuperation du detail ghistorique pour un item
  1520. }else{
  1521. $filters['scope'] = $_['scope'];
  1522. if(isset($_['uid'])) $filters['uid'] = $_['uid'];
  1523. if(!empty($_['keyword'])) $filters['comment:LIKE'] = '%'.$_['keyword'].'%';
  1524. foreach(History::loadAll($filters,array('sort DESC')) as $history){
  1525. $row = $history->toArray();
  1526. $row['type'] = History::types($row['type']);
  1527. $row['comment'] = html_entity_decode($row['comment'],ENT_QUOTES,'UTF-8');
  1528. $row['created'] =array(
  1529. 'fullname'=>complete_date($row['created']),
  1530. 'time'=>date('H:i',$row['created'])
  1531. );
  1532. $user = User::byLogin($row['creator']);
  1533. $row['creator'] = array('fullname'=>(!is_null($user->login) ? $user->fullName() : $row['creator']));
  1534. $response['rows'][] = $row;
  1535. }
  1536. }
  1537. });
  1538. Action::register('history_importance',function(&$response){
  1539. global $myUser,$_;
  1540. User::check_access('history','edit');
  1541. $item = History::provide();
  1542. if(is_null($item->id)) return;
  1543. $item->importance = $_['importance'];
  1544. $item->save();
  1545. $response = $item->toArray();
  1546. });
  1547. Action::register('history_save',function(&$response){
  1548. global $myUser,$_,$myFirm;
  1549. User::check_access('history','edit');
  1550. $item = History::provide();
  1551. if(!$item) return;
  1552. if(isset($_['comment'])) $item->comment = $_['comment'];
  1553. $item->uid = $_['uid'];
  1554. //Si pas d'ordre défini on récupere l'ordre maximum
  1555. if(empty($_['sort'])) {
  1556. $query = History::staticQuery('SELECT MAX(sort) maxsort FROM {{table}} WHERE scope = ? AND uid= ? ',array($_['scope'],$item->uid));
  1557. $row = $query->fetch();
  1558. $_['sort'] = $row['maxsort']+1;
  1559. }
  1560. //Si l'ordre est intercalé a la place de l'ordre "replaceSort", on décale la rangée de "replaceSort" à n et on attribute "replaceSort" à l'élement
  1561. if(!empty($_['replaceSort'])) {
  1562. $_['sort'] = $_['replaceSort'];
  1563. History::staticQuery('UPDATE {{table}} SET sort = sort+1 WHERE sort >= ? AND scope = ? AND uid= ?',
  1564. array($_['replaceSort'],$_['scope'],$item->uid)) ;
  1565. }
  1566. $item->sort = $_['sort'];
  1567. $item->scope = $_['scope'];
  1568. $item->importance = $_['importance'];
  1569. $item->type = History::TYPE_COMMENT;
  1570. $item->meta = json_encode(array('url'=>$_['meta']));
  1571. $item->save();
  1572. if(!is_null($item->comment) && $myFirm->has_plugin('fr.core.notification')){
  1573. $mentionned = get_mention($item->comment);
  1574. if(isset($mentionned['user']) && !empty($mentionned['user'])){
  1575. $recipients = array();
  1576. foreach($mentionned['user'] as $user)
  1577. $recipients[] = $user->login;
  1578. $url = array();
  1579. if(!is_null($item->meta)){
  1580. $data = json_decode($item->meta,true);
  1581. foreach($data['url'] as $parameter=>$value)
  1582. $url[] = $parameter."=".$value;
  1583. }
  1584. $url = empty($url) ? '' : '?'.implode('&',$url);
  1585. // GESTION ENVOI NOTIFICATION
  1586. Plugin::callHook('emit_notification',array(array(
  1587. 'label' => 'Vous avez été mentionné dans un commentaire...',
  1588. 'html' => 'Un utilisateur vous a mentionné '.$item->scope,
  1589. 'type' => "notice",
  1590. 'meta' => array('link' => ROOT_URL.'/index.php'.$url),
  1591. 'recipients' => $recipients
  1592. )
  1593. ));
  1594. }
  1595. }
  1596. $response = $item->toArray();
  1597. });
  1598. Action::register('history_delete',function(&$response){
  1599. global $myUser,$_;
  1600. User::check_access('history','delete');
  1601. History::deleteById($_['id']);
  1602. });
  1603. /* CONTACT */
  1604. Action::register('contact_autocomplete',function(&$response){
  1605. global $myUser,$_;
  1606. if(!$myUser->can('contact','read')) throw new Exception("Vous n'avez pas acces aux contacts");
  1607. $response['rows'] = array();
  1608. $query = 'SELECT * FROM {{table}} p WHERE 1 ';
  1609. if(isset($_['keyword'])){
  1610. $query .= ' AND (p.firstname LIKE ? OR p.name LIKE ?) ';
  1611. $data = array('%'.$_['keyword'].'%','%'.$_['keyword'].'%');
  1612. }
  1613. if(isset($_['data']) && isset($_['data']['scope'])){
  1614. $query .= ' AND p.scope= ? ';
  1615. $data[]= $_['data']['scope'];
  1616. }
  1617. if(isset($_['data']) && isset($_['data']['uid'])){
  1618. $uids = array();
  1619. foreach($_['data']['uid'] as $uid){
  1620. $uids[] = '?';
  1621. $data[]= $uid;
  1622. }
  1623. $query .= ' AND p.uid IN ('.implode(',',$uids).') ';
  1624. }
  1625. $query .= ' ORDER BY name,firstname LIMIT 15';
  1626. foreach(ContactPerson::staticQuery($query,$data,true) as $item){
  1627. $response['rows'][] = array(
  1628. 'label'=>html_decode_utf8($item->fullName()),
  1629. 'id'=>$item->id,
  1630. 'job'=>$item->job
  1631. );
  1632. }
  1633. });
  1634. Action::register('contact_by_uid',function(&$response){
  1635. global $myUser,$_;
  1636. if(!$myUser->can('contact','read')) throw new Exception("Vous n'avez pas acces aux contacts");
  1637. $response['items'] = array();
  1638. $items = $_['items'];
  1639. foreach(ContactPerson::loadAll(array('id:IN'=>implode(',',$items))) as $item){
  1640. $row = $item->toArray();
  1641. $row['label'] = $item->fullname();
  1642. $row['job'] = $item->job;
  1643. $row['id'] = $item->id;
  1644. $response['items'][$item->id] = $row;
  1645. }
  1646. });
  1647. /** Gestion des fichiers **/
  1648. Action::register('file_search',function(&$response){
  1649. global $myUser, $_, $conf;
  1650. User::check_access('file','read');
  1651. $programRoot = rtrim(File::dir(),SLASH);
  1652. $root = !empty($_['root']) ? $programRoot.SLASH.trim($_['root'],SLASH) : $programRoot;
  1653. if(isset($_['folder']) && ($_['folder']=='.' || $_['folder']=='..')) $_['folder']=='';
  1654. $target = (!empty($_['folder'])) ? $programRoot.SLASH.rtrim($_['folder'],SLASH) : $root;
  1655. $path = explode(SLASH,str_replace($root,'',$target));
  1656. $path = array_values(array_filter($path));
  1657. $files = glob($root.SLASH.'*');
  1658. $currentPath = '';
  1659. for($i=0;$i<count($path);$i++){
  1660. $currentPath.= $path[$i].SLASH;
  1661. $files = array_merge($files,glob(File::dir().$currentPath.'*'));
  1662. }
  1663. $response['tree'] = array();
  1664. foreach($files as $file){
  1665. if(!is_dir($file)) continue;
  1666. $relativePath = str_replace( $root.SLASH,'',$file);
  1667. $response['tree'][] = $relativePath;
  1668. }
  1669. });
  1670. /** CUSTOM API */
  1671. // pour obtenir un schema de toutes les api actives : http://url.com/api/schema?pretty
  1672. Action::register('api',function(&$response){
  1673. /* CORE API */
  1674. //Infos api
  1675. $api = new Api("core", "Api du coeur applicatif");
  1676. $api->route('infos','retourne les informations sur l\'environnement','GET',function($request,&$response){
  1677. global $myUser,$databases_credentials;
  1678. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1679. $repository = '';
  1680. if(file_exists(__DIR__.SLASH.'.git'.SLASH.'config')){
  1681. $stream = file_get_contents(__DIR__.SLASH.'.git'.SLASH.'config');
  1682. preg_match('|url = (.*\.fr)[:/]([^\n]*)|is', $stream,$match);
  1683. $repository = $match[2];
  1684. $repositoryUrl = preg_replace('|[^@]*@|i','http://',$match[1]).'/'.$match[2];
  1685. }
  1686. if(file_exists(__DIR__.SLASH.'.git'.SLASH.'refs'.SLASH.'heads'.SLASH.'master'))
  1687. $commitVersion = str_replace(array("\n","\r"),"",file_get_contents(__DIR__.SLASH.'.git'.SLASH.'refs'.SLASH.'heads'.SLASH.'master'));
  1688. $response['application']['label'] = PROGRAM_NAME;
  1689. $response['application']['version'] = SOURCE_VERSION;
  1690. $response['application']['versionning']['type'] = 'git';
  1691. $response['application']['versionning']['repository'] = $repository;
  1692. $response['application']['versionning']['repository_url'] = $repositoryUrl;
  1693. $response['application']['versionning']['commit_version'] = $commitVersion;
  1694. $response['application']['timezone'] = TIME_ZONE;
  1695. $response['php']['version'] = phpversion();
  1696. $response['apache']['version'] = apache_get_version();
  1697. $response['databases'] = array();
  1698. foreach ($databases_credentials as $key => $value) {
  1699. unset($value['password']);
  1700. $value['uid'] = $key;
  1701. $response['databases'][] = $value;
  1702. }
  1703. $response['os']['type'] = PHP_OS;
  1704. $response['os']['time'] = time();
  1705. });
  1706. $api->route('token','retourne un jwt token en fonction des identifiants fournis sur l\'environnement','POST',function($request,&$response){
  1707. $_ = json_decode($request['body'],true);
  1708. if(!isset($_['api_id']) || !isset($_['api_secret'])) throw new Exception("Api Credentials are missing",401);
  1709. global $conf;
  1710. if(empty($conf->get('jwtauth_secret'))) throw new Exception('JWT secret is missing in core',501);
  1711. if(session_status() == PHP_SESSION_ACTIVE) session_destroy();
  1712. session_start();
  1713. $apiKey = UserPreference::load(array('key'=>'api_id','value'=>encrypt($_['api_id'])));
  1714. if(!$apiKey) throw new Exception('Api id not found',404);
  1715. $apiSecret = UserPreference::load(array('key'=>'api_secret','user'=>$apiKey->user,'value'=>encrypt($_['api_secret'])));
  1716. if(!$apiSecret) throw new Exception('Bad api secret',401);
  1717. $apiEnabled = UserPreference::load(array('key'=>'api_enabled','user'=>$apiKey->user,'value'=>1));
  1718. if(!$apiEnabled) throw new Exception('Api is not enabled for this account',401);
  1719. global $myUser,$myFirm;
  1720. $myUser = User::connectLogin($apiSecret->user);
  1721. if(!$myUser || !$myUser->connected()) throw new Exception('Bad credentials',401);
  1722. if(file_exists('enabled.maintenance') && $myUser->superadmin != 1) throw new Exception('Maintenance is enabled, only super admin can connects',403);
  1723. $_SESSION['currentUser'] = serialize($myUser);
  1724. $_SESSION['firm'] = serialize($myFirm);
  1725. $response['session'] = session_id();
  1726. $json = array();
  1727. $json['exp'] = strtotime('+8hours');
  1728. $json['attributes'] = array(
  1729. 'session_id' => session_id(),
  1730. 'user' => $myUser->login
  1731. );
  1732. $response['token'] = JWToken::createFromJson($json,$conf->get('jwtauth_secret'));
  1733. });
  1734. //right api
  1735. $api->route('rights','retourne la liste des droits du logiciel','GET',function($request,&$response){
  1736. global $myUser;
  1737. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1738. $response['rights'] = array();
  1739. if(isset($request['parameters']['sort'])) throw new Exception("Sort is not implemented for firms",501);
  1740. if(isset($request['parameters']['filter'])) throw new Exception("Filter is not implemented for firms",501);
  1741. $limit = isset($request['parameters']['limit']) ? array($request['parameters']['limit']) : array();
  1742. foreach (Right::loadAll(array(),array(),$limit) as $right) {
  1743. $row = $right->toArray();
  1744. $response['rights'][] = $row;
  1745. }
  1746. });
  1747. $api->route('rights/[rightid]','ajoute/modifie un droit du logiciel','PUT',function($request,&$response){
  1748. global $myUser;
  1749. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1750. $response['right'] = array();
  1751. //Création
  1752. $_ = $request['parameters'];
  1753. $form = json_decode($request['body'],true);
  1754. if(!$form) throw new Exception("Invalid JSON body",400);
  1755. User::check_access('right','edit');
  1756. if(!empty($request['pathes'])){
  1757. $right = Right::getById($request['pathes'][0]);
  1758. if(empty($right->id)) throw new Exception("Right not found", 404);
  1759. $response['code'] = 200; //Modifié
  1760. }else{
  1761. $right = new right();
  1762. if(!isset($form['rank']) || empty($form['rank'])) throw new Exception("L'id du rang est obligatoire",400);
  1763. if(!isset($form['scope']) || empty($form['scope'])) throw new Exception("Le nom de la scope est obligatoire",400);
  1764. if(!isset($form['firm']) || empty($form['firm'])) throw new Exception("L'id de l'établissement est obligatoire",400);
  1765. $response['code'] = 201; //Créé
  1766. }
  1767. //Check si le rang existe
  1768. $rank = Rank::getById($form['rank']);
  1769. if(empty($rank->id)) throw new Exception("Rank not found", 400);
  1770. //Check si la firm existe
  1771. $firm = Firm::getById($form['firm']);
  1772. if(empty($firm->id)) throw new Exception("Firm not found", 400);
  1773. //Check si la scope existe
  1774. $scopes = array();
  1775. Plugin::callHook('section',array(&$scopes));
  1776. $find = false;
  1777. foreach($scopes as $scope=>$description){
  1778. if ($scope==$form['scope']){
  1779. $find = true;
  1780. break;
  1781. }
  1782. }
  1783. if (!$find) throw new Exception("Section not found", 400);
  1784. if(isset($form['targetUid'])) $right->targetUid = $form['targetUid'];
  1785. if(isset($form['scope'])) $right->scope = $form['scope'];
  1786. if(isset($form['firm'])) $right->firm = $form['firm'];
  1787. if(isset($form['read'])) $right->read = $form['read'];
  1788. if(isset($form['edit'])) $right->edit = $form['edit'];
  1789. if(isset($form['delete'])) $right->delete = $form['delete'];
  1790. if(isset($form['configure'])) $right->configure = $form['configure'];
  1791. $right->save();
  1792. Log::put("Création/Modification de droit ".$right->toText(),'Droit');
  1793. $response['right'] = array('id'=>$right->id,'scope'=>$right->scope);
  1794. });
  1795. $api->route('rights/rightid','Supprime un rang du logiciel','DELETE',function($request,&$response){
  1796. global $myUser;
  1797. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1798. if(empty($request['pathes'])) throw new Exception("You must specify right id", 400);
  1799. User::check_access('right','delete');
  1800. $right = Right::getById($request['pathes'][0]);
  1801. if(!$right) throw new Exception("Right not found",404);
  1802. $right->deleteById($right->id);
  1803. Log::put("Suppression du rang ".$right->toText(),'Rang');
  1804. $response['code'] = 204;
  1805. });
  1806. //rank api
  1807. $api->route('ranks','retourne la liste des rangs du logiciel','GET',function($request,&$response){
  1808. global $myUser;
  1809. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1810. $response['ranks'] = array();
  1811. if(isset($request['parameters']['sort'])) throw new Exception("Sort is not implemented for firms",501);
  1812. if(isset($request['parameters']['filter'])) throw new Exception("Filter is not implemented for firms",501);
  1813. $limit = isset($request['parameters']['limit']) ? array($request['parameters']['limit']) : array();
  1814. foreach (Rank::loadAll(array(),array(),$limit) as $rank) {
  1815. $row = $rank->toArray();
  1816. $response['ranks'][] = $row;
  1817. }
  1818. });
  1819. $api->route('ranks/[rankid]','ajoute/modifie un rang du logiciel','PUT',function($request,&$response){
  1820. global $myUser;
  1821. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1822. $response['rank'] = array();
  1823. //Création
  1824. $_ = $request['parameters'];
  1825. $form = json_decode($request['body'],true);
  1826. if(!$form) throw new Exception("Invalid JSON body",400);
  1827. User::check_access('rank','edit');
  1828. if(!empty($request['pathes'])){
  1829. $rank = Rank::getById($request['pathes'][0]);
  1830. if(empty($rank->id)) throw new Exception("Rank not found", 404);
  1831. $response['code'] = 200; //Modifié
  1832. }else{
  1833. $rank = new rank();
  1834. if(!isset($form['label']) || empty($form['label'])) throw new Exception("Le libellé est obligatoire",400);
  1835. //Check si un rang n'existe pas déjà avec ce label
  1836. if(Rank::load(array('label'=>$form['label']))) throw new Exception("Un rang existe déjà avec ce nom",400);
  1837. $rank->label = $form['label'];
  1838. $response['code'] = 201; //Créé
  1839. }
  1840. if(isset($form['label'])) $rank->label = $form['label'];
  1841. if(isset($form['description'])) $rank->description = $form['description'];
  1842. $rank->save();
  1843. Log::put("Création/Modification de rang ".$rank->toText(),'Rang');
  1844. $response['rank'] = array('id'=>$rank->id,'label'=>$rank->label);
  1845. });
  1846. $api->route('ranks/rankid','Supprime un rang du logiciel','DELETE',function($request,&$response){
  1847. global $myUser;
  1848. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1849. if(empty($request['pathes'])) throw new Exception("You must specify rank id", 400);
  1850. User::check_access('rank','delete');
  1851. $rank = Rank::getById($request['pathes'][0]);
  1852. if(!$rank) throw new Exception("Rank not found",404);
  1853. foreach(UserFirmRank::loadAll(array('rank'=>$rank->id)) as $ufrLink)
  1854. UserFirmRank::deleteById($ufrLink->id);
  1855. $rank->deleteById($rank->id);
  1856. Log::put("Suppression du rang ".$rank->toText(),'Rang');
  1857. $response['code'] = 204;
  1858. });
  1859. //firm api
  1860. $api->route('firms','retourne la liste des établissements du logiciel','GET',function($request,&$response){
  1861. global $myUser;
  1862. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1863. $response['firms'] = array();
  1864. if(isset($request['parameters']['sort'])) throw new Exception("Sort is not implemented for firms",501);
  1865. if(isset($request['parameters']['filter'])) throw new Exception("Filter is not implemented for firms",501);
  1866. $limit = isset($request['parameters']['limit']) ? array($request['parameters']['limit']) : array();
  1867. foreach (Firm::loadAll(array(),array(),$limit) as $i=>$firm) {
  1868. $row = $firm->toArray();
  1869. $response['firms'][] = $row;
  1870. }
  1871. });
  1872. $api->route('firms/[firmid]','ajoute/modifie un établissement du logiciel','PUT',function($request,&$response){
  1873. global $myUser;
  1874. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1875. $response['firm'] = array();
  1876. //Création
  1877. $_ = $request['parameters'];
  1878. $form = json_decode($request['body'],true);
  1879. if(!$form) throw new Exception("Invalid JSON body",400);
  1880. User::check_access('firm','edit');
  1881. if(!empty($request['pathes'])){
  1882. $firm = Firm::getById($request['pathes'][0]);
  1883. if(empty($firm->id)) throw new Exception("Firm not found", 404);
  1884. $response['code'] = 200; //Modifié
  1885. }else{
  1886. $firm = new Firm();
  1887. if(!isset($form['label']) || empty($form['label'])) throw new Exception("Le libellé est obligatoire",400);
  1888. if(!isset($form['mail']) || empty($form['mail'])) throw new Exception('Le champ "Mail"est obligatoire',400);
  1889. //Check si une firm n'existe pas déjà avec ce label
  1890. if(Firm::load(array('label'=>$form['label']))) throw new Exception("Un établissement existe déjà avec ce nom",400);
  1891. $firm->label = $form['label'];
  1892. $response['code'] = 201; //Créé
  1893. }
  1894. if(isset($form['label'])) $firm->label = $form['label'];
  1895. if(isset($form['description'])) $firm->description = $form['description'];
  1896. if(isset($form['mail'])) $firm->mail = $form['mail'];
  1897. if(isset($form['phone'])) $firm->phone = $form['phone'];
  1898. if(isset($form['fax'])) $firm->fax = $form['fax'];
  1899. if(isset($form['street'])) $firm->street = $form['street'];
  1900. if(isset($form['street2'])) $firm->street2 = $form['street2'];
  1901. if(isset($form['city'])) $firm->city = $form['city'];
  1902. if(isset($form['zipcode'])) $firm->zipcode = $form['zipcode'];
  1903. if(isset($form['siret'])) $firm->siret = $form['siret'];
  1904. if(isset($form['iban'])) $firm->iban = $form['iban'];
  1905. $firm->save();
  1906. Log::put("Création/Modification de l'établissement ".$firm->toText(),'Etablissement');
  1907. $response['firm'] = array('id'=>$firm->id,'label'=>$firm->label);
  1908. });
  1909. $api->route('firms/firmid','Supprime un établissement du logiciel','DELETE',function($request,&$response){
  1910. global $myUser;
  1911. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1912. if(empty($request['pathes'])) throw new Exception("You must specify firm id", 400);
  1913. User::check_access('firm','delete');
  1914. $firm = Firm::getById($request['pathes'][0]);
  1915. if(!$firm) throw new Exception("Firm not found",404);
  1916. foreach(UserFirmRank::loadAll(array('firm'=>$firm->id)) as $ufrLink)
  1917. UserFirmRank::deleteById($ufrLink->id);
  1918. $firm->deleteById($firm->id);
  1919. Log::put("Suppression de l'établissement ".$firm->toText(),'Etablissement');
  1920. $response['code'] = 204;
  1921. });
  1922. //user api
  1923. $api->route('account','retourne les informations du compte connecté','GET',function($request,&$response){
  1924. global $myUser;
  1925. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1926. $response['account'] = $myUser->toArray();
  1927. unset($response['account']['password']);
  1928. });
  1929. //user api
  1930. $api->route('users','retourne la liste des utilisateurs du logiciel','GET',function($request,&$response){
  1931. global $myUser;
  1932. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1933. $response['users'] = array();
  1934. if(isset($request['parameters']['sort'])) throw new Exception("Sort is not implemented for users",501);
  1935. if(isset($request['parameters']['filter'])) throw new Exception("Filter is not implemented for users",501);
  1936. foreach (User::getAll(array('right'=>false)) as $i=>$user) {
  1937. if(isset($request['parameters']['limit']) && $request['parameters']['limit']==$i) break;
  1938. $row = $user->toArray();
  1939. unset($row['password']);
  1940. unset($row['manager']);
  1941. $row['origin'] = !isset($row['id']) ? 'plugin': 'database';
  1942. $response['users'][] = $row;
  1943. }
  1944. });
  1945. $api->route('users/[userid]','ajoute/modifie un utilisateur du logiciel','PUT',function($request,&$response){
  1946. global $myUser;
  1947. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1948. $response['user'] = array();
  1949. //Création
  1950. $_ = $request['parameters'];
  1951. $form = json_decode($request['body'],true);
  1952. if(!$form) throw new Exception("Invalid JSON body",400);
  1953. User::check_access('user','edit');
  1954. if(!empty($request['pathes'])){
  1955. $user = User::byLogin($request['pathes'][0]);
  1956. if(empty($user->login)) throw new Exception("User not found", 404);
  1957. $response['code'] = 200; //Modifié
  1958. }else{
  1959. $user = new User();
  1960. if(!isset($form['login']) || empty($form['login'])) throw new Exception("Identifiant obligatoire",400);
  1961. if(!isset($form['password']) || empty($form['password'])) throw new Exception("Mot de passe obligatoire",400);
  1962. if(!isset($form['mail']) || empty($form['mail'])) throw new Exception('Le champ "Mail"est obligatoire',400);
  1963. foreach(User::getAll(array('right'=>false)) as $existingUser)
  1964. if($existingUser->mail == trim($_['mail'])) throw new Exception("Un utilisateur existe déjà avec cette adresse e-mail");
  1965. //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)
  1966. if(User::load(array('login'=>$form['login']))) throw new Exception("Un utilisateur existe déjà avec cet identifiant",400);
  1967. $user->login = $form['login'];
  1968. $response['code'] = 201; //Créé
  1969. }
  1970. if(!empty(trim($form['password']))){
  1971. $passwordErrors = User::check_password_format(html_entity_decode($form['password']));
  1972. 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);
  1973. 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);
  1974. $user->password = User::password_encrypt($form['password']);
  1975. $user->preference('passwordTime',time());
  1976. }
  1977. if(isset($form['firstname'])) $user->firstname = mb_ucfirst(mb_strtolower($form['firstname']));
  1978. if(isset($form['name'])) $user->name = mb_strtoupper($form['name']);
  1979. if(isset($form['mail'])) $user->mail = $form['mail'];
  1980. $user->state = User::ACTIVE;
  1981. if(isset($form['manager'])) $user->manager = $form['manager'];
  1982. $user->save();
  1983. User::getAll(array('right'=>true,'force'=>true));
  1984. Log::put("Création/Modification de l'utilisateur ".$user->toText(),'Utilisateur');
  1985. $response['user'] = array('id'=>$user->id,'login'=>$user->login);
  1986. });
  1987. $api->route('users/userid','Supprime un utilisateur du logiciel','DELETE',function($request,&$response){
  1988. global $myUser;
  1989. if(!$myUser->connected()) throw new Exception("Credentials are missing",401);
  1990. if(empty($request['pathes'])) throw new Exception("You must spcify user login", 400);
  1991. User::check_access('user','delete');
  1992. $user = User::byLogin($request['pathes'][0]);
  1993. if(!$user) throw new Exception("User not found",404);
  1994. if($user->superadmin == 1) throw new Exception("You can't delete superadmin account",403);
  1995. if($user->login == $myUser->login) throw new Exception("You can't delete your own account",403);
  1996. if(empty($user->id)) throw new Exception("You cant delete no db account", 400);
  1997. $user = User::getById($user->id);
  1998. $user->state = User::INACTIVE;
  1999. $user->save();
  2000. foreach(UserFirmRank::loadAll(array('user'=>$user->login)) as $ufrLink)
  2001. UserFirmRank::deleteById($ufrLink->id);
  2002. if(isset($_SESSION['users_rights'])) unset($_SESSION['users_rights']);
  2003. if(isset($_SESSION['users_norights'])) unset($_SESSION['users_norights']);
  2004. Log::put("Suppression de l'utilisateur ".$user->toText(),'Utilisateur');
  2005. $response['code'] = 204;
  2006. });
  2007. $api->register();
  2008. /* FIN CORE API */
  2009. Api::run();
  2010. });
  2011. /** CUSTOM REWRITE */
  2012. Action::register('rewrite',function(&$response){
  2013. try{
  2014. $root = substr($_SERVER['SCRIPT_NAME'], 0,strrpos($_SERVER['SCRIPT_NAME'] , '/'));
  2015. $requested = substr($_SERVER['REQUEST_URI'], strlen($root)+1);
  2016. ob_start();
  2017. Plugin::callHook('rewrite',array($requested));
  2018. $stream = ob_get_clean();
  2019. if($stream !='') echo $stream;
  2020. }catch(Exception $e){
  2021. exit('<div style="width:300px;margin:30px auto;padding:15px;background:#cecece;text-align:center;font-family:Arial">'.$e->getMessage().'</div>');
  2022. }
  2023. });
  2024. /** ACTIONS DE PLUGINS */
  2025. //nouveau system d'action plugin
  2026. if(isset($GLOBALS['actions'][$_['action']])){
  2027. Action::write($GLOBALS['actions'][$_['action']]);
  2028. }else{
  2029. //compatibilité ancien système d'action plugin (deprecated)
  2030. Plugin::callHook('action');
  2031. }
  2032. ?>