factorize code for ax key path
[platal.git] / modules / fusionax.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2007 Polytechnique.org *
4 * http://opensource.polytechnique.org/ *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the Free Software *
18 * Foundation, Inc., *
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
20 ***************************************************************************/
21
22 class FusionAxModule extends PLModule{
23
24 var $ax_xorg_rsa_key = dirname(__FILE__).'/../configs/ax_xorg_rsa.pem';
25
26 function handlers()
27 {
28 return array(
29 'fusionax' => $this->make_hook('index', AUTH_MDP, 'admin'),
30 'fusionax/import' => $this->make_hook('import', AUTH_MDP,'admin'),
31 'fusionax/ids' => $this->make_hook('ids', AUTH_MDP, 'admin'),
32 'fusionax/misc' => $this->make_hook('misc', AUTH_MDP, 'admin'),
33 );
34 }
35
36 function handler_index(&$page)
37 {
38 global $globals;
39 $page->changeTpl('fusionax/index.tpl');
40 $page->assign('xorg_title','Polytechnique.org - Fusion des annuaires');
41 if (isset($globals->fusionax) &&
42 isset($globals->fusionax->LastUpdate)) {
43 $page->assign(
44 'lastimport',
45 date("d-m-Y",$globals->fusionax->LastUpdate));
46 }
47 }
48
49 /** Import de l'annuaire de l'AX depuis l'export situé sur leur serveur */
50 function handler_import(&$page, $action = 'index', $fileSQL = '')
51 {
52 if ($action == 'index') {
53 $page->changeTpl('fusionax/import.tpl');
54 $page->addJsLink('jquery.js');
55 global $globals;
56 if (isset($globals->fusionax) &&
57 isset($globals->fusionax->LastUpdate)) {
58 $page->assign(
59 'lastimport',
60 "le ".date("d/m/Y à H:i",$globals->fusionax->LastUpdate));
61 }
62 if (!file_exists($this->ax_xorg_rsa_key)) {
63 $page->assign(
64 'keymissing',
65 $this->ax_xorg_rsa_key);
66 }
67 return;
68 }
69
70 // toutes les actions sont faites en ajax en utilisant jquery
71 header("Content-type: text/javascript; charset=utf-8");
72
73 // log des actions
74 $report = array();
75
76 // création d'un fichier temporaire si nécessaire
77 if (Env::has('tmpdir')) {
78 $tmpdir = Env::v('tmpdir');
79 } else {
80 $tmpdir = tempnam('/tmp', 'fusionax');
81 unlink($tmpdir);
82 mkdir($tmpdir);
83 chmod($tmpdir, 0700);
84 // copie la clef d'authentification (paire de clef RSA dont la
85 // partie publique est sur polytechniciens.com)
86 if (!copy(
87 $this->ax_xorg_rsa_key,
88 $tmpdir.'/ax_xorg_rsa'))
89 $report[] = 'Impossible de copier la clef pour se logger '.
90 'au serveur AX';
91 chmod($tmpdir.'/ax_xorg_rsa', 0600);
92 }
93
94 $modulepath = realpath(dirname(__FILE__).'/fusionax/').'/';
95 $olddir = getcwd();
96 chdir($tmpdir);
97
98 if ($action == 'launch') {
99 // lancement : connexion en ssh et récupération du fichier depuis
100 // polyechniciens.com, décompression de l'archive et séparation en
101 // fichiers par tables
102 exec($modulepath.'import-ax.sh', $report);
103 $report[] = utf8_decode('Récupération du fichier terminé.');
104 $report[] = 'Import dans la base en cours...';
105 $next = 'integrateSQL';
106 } else if ($action == 'integrateSQL') {
107 // intégration des données dans la base MySQL
108 // liste des fichiers sql à exécuter
109 $filesSQL = array(
110 'Activites.sql',
111 'Adresses.sql',
112 'Anciens.sql',
113 'Formations.sql',
114 'Entreprises.sql');
115 if ($fileSQL != '') {
116 // récupère le contenu du fichier sql
117 $queries = explode(';',file_get_contents($modulepath.$fileSQL));
118 foreach ($queries as $q) if (trim($q)) {
119 // coupe le fichier en requêtes individuelles
120 if (substr($q,0,2) == '--') {
121 // affiche les commentaires dans le report
122 $lines = explode("\n",$q);
123 $l = $lines[0];
124 $report[] = addslashes(utf8_decode($l));
125 }
126 // exécute la requête
127 XDB::execute($q);
128 }
129 // trouve le prochain fichier à exécuter
130 $trans = array_flip($filesSQL);
131 $nextfile = $trans[$fileSQL] + 1;
132 } else {
133 $nextfile = 0;
134 }
135 if (!isset($filesSQL[$nextfile])) {
136 // tous les fichiers ont été exécutés, on passe à l'étape
137 // suivante
138 $next = 'clean';
139 } else {
140 // on passe au fichier suivant
141 $next = 'integrateSQL/'.$filesSQL[$nextfile];
142 }
143 } else if ($action == 'clean') {
144 // nettoyage du fichier temporaire
145 chdir($olddir);
146 exec("rm -rf $tmpdir", $report);
147 $report[] = 'Fin de l\'import';
148 global $globals;
149 // met à jour la date de dernier import
150 $globals->change_dynamic_config(
151 array('LastUpdate' => time()),
152 'FusionAx');
153 }
154 $tmpdir = getcwd();
155 chdir($olddir);
156 foreach($report as $t)
157 // affiche les lignes de report
158 echo "$('#fusionax_import').append('".utf8_encode($t)."<br/>');\n";
159 if (isset($next)) {
160 // lance le prochain script s'il y en a un
161 echo "$.getScript('fusionax/import/".$next."?tmpdir=".
162 urlencode($tmpdir)."');";
163 }
164 // exit pour ne pas afficher la page template par défaut
165 exit;
166 }
167
168 /** Lier les identifiants d'un ancien dans les deux annuaires
169 * @param user_id identifiant dans l'annuaire X.org
170 * @param matricule_ax identifiant dans l'annuaire de l'AX
171 * @return 0 si la liaison a échoué, 1 sinon
172 */
173 private static function link_by_ids($user_id, $matricule_ax)
174 {
175 if (!XDB::execute("
176 UPDATE fusionax_import AS i
177 INNER JOIN fusionax_xorg_anciens AS u
178 SET
179 u.matricule_ax = i.id_ancien,
180 i.user_id = u.user_id,
181 i.date_match_id = NOW()
182 WHERE
183 i.id_ancien = {?} AND u.user_id = {?} AND (
184 u.matricule_ax != {?} OR u.matricule_ax IS NULL OR
185 i.user_id != {?} OR i.user_id IS NULL)",
186 $matricule_ax,
187 $user_id,
188 $matricule_ax,
189 $user_id))
190 {
191 return 0;
192 }
193 return XDB::affectedRows() / 2;
194 }
195
196 /** Recherche automatique d'anciens à lier entre les deux annuaires
197 * @param limit nombre d'anciens à trouver au max
198 * @param sure si true, ne trouve que des anciens qui sont quasi sûrs
199 * @return un XOrgDBIterator sur les entrées avec display_name, promo,
200 * user_id, id_ancien et display_name_ax
201 */
202 private static function find_easy_to_link($limit = 10, $sure = false)
203 {
204 $easy_to_link = XDB::iterator("
205 SELECT
206 xorg.display_name, xorg.promo, xorg.user_id, ax.id_ancien,
207 CONCAT(ax.prenom,' ',ax.nom_complet,' (X ',ax.promotion_etude,')')
208 AS display_name_ax,
209 COUNT(*) AS nbMatches
210 FROM fusionax_anciens AS ax
211 INNER JOIN fusionax_import AS i ON (
212 i.id_ancien = ax.id_ancien AND i.user_id IS NULL)
213 LEFT JOIN fusionax_xorg_anciens AS xorg ON (
214 xorg.matricule_ax IS NULL AND
215 ax.Nom_complet = xorg.nom AND
216 ax.prenom = xorg.prenom AND
217 xorg.promo = ax.promotion_etude)
218 GROUP BY xorg.user_id
219 HAVING
220 xorg.user_id IS NOT NULL AND
221 nbMatches = 1
222 ".($limit?('LIMIT '.$limit):''));
223 if ($easy_to_link->total() > 0 || $sure) {
224 return $easy_to_link;
225 }
226 return XDB::iterator("
227 SELECT
228 xorg.display_name, xorg.promo, xorg.user_id, ax.id_ancien,
229 CONCAT(ax.prenom,' ',ax.nom_complet,' (X ',ax.promotion_etude,')')
230 AS display_name_ax,
231 COUNT(*) AS nbMatches
232 FROM fusionax_anciens AS ax
233 INNER JOIN fusionax_import AS i ON (
234 i.id_ancien = ax.id_ancien AND i.user_id IS NULL)
235 LEFT JOIN fusionax_xorg_anciens AS xorg ON (
236 xorg.matricule_ax IS NULL AND
237 (ax.Nom_complet = xorg.nom
238 OR ax.Nom_complet LIKE CONCAT(xorg.nom,' %')
239 OR ax.Nom_complet LIKE CONCAT(xorg.nom,'-%')
240 OR ax.Nom_usuel = xorg.nom
241 OR xorg.nom LIKE CONCAT('% ',ax.Nom_complet)) AND
242 xorg.promo < ax.promotion_etude + 2 AND
243 xorg.promo > ax.promotion_etude - 2)
244 GROUP BY xorg.user_id
245 HAVING
246 xorg.user_id IS NOT NULL AND
247 nbMatches = 1
248 ".($limit?('LIMIT '.$limit):''));
249 }
250
251 /** Module de mise en correspondance les ids */
252 function handler_ids(
253 &$page,
254 $part = 'main',
255 $user_id = null,
256 $matricule_ax = null)
257 {
258 global $globals;
259 $page->addJsLink('jquery.js');
260
261 $page->assign(
262 'xorg_title',
263 'Polytechnique.org - Fusion - Mise en correspondance simple');
264 if ($part == 'missingInAX')
265 {
266 // locate all persons from this database that are not in AX's
267 $page->changeTpl('fusionax/idsMissingInAx.tpl');
268 $missingInAX = XDB::iterator("SELECT
269 u.promo, u.user_id, u.display_name
270 FROM fusionax_xorg_anciens AS u
271 WHERE u.matricule_ax IS NULL
272 LIMIT 20");
273 $page->assign('missingInAX', $missingInAX);
274 return;
275 }
276 if ($part == 'missingInXorg')
277 {
278 // locate all persons from AX's database that are not here
279 $page->changeTpl('fusionax/idsMissingInXorg.tpl');
280 $missingInXorg = XDB::iterator("SELECT
281 a.promotion_etude AS promo,
282 CONCAT(a.prenom, ' ',a.Nom_usuel) AS display_name,
283 a.id_ancien
284 FROM fusionax_import
285 INNER JOIN fusionax_anciens AS a USING (id_ancien)
286 WHERE fusionax_import.user_id IS NULL
287 LIMIT 20");
288 $page->assign('missingInXorg', $missingInXorg);
289 return;
290 }
291 if ($part == 'link')
292 {
293 FusionAxModule::link_by_ids($user_id,$matricule_ax);
294 exit;
295 }
296 if ($part == 'linknext')
297 {
298 $linksToDo = FusionAxModule::find_easy_to_link(10);
299 while ($l = $linksToDo->next())
300 {
301 FusionAxModule::link_by_ids($l['user_id'],$l['id_ancien']);
302 }
303 pl_redirect('fusionax/ids#autolink');
304 }
305 if ($part == 'linkall')
306 {
307 $linksToDo = FusionAxModule::find_easy_to_link(0);
308 while ($l = $linksToDo->next())
309 {
310 FusionAxModule::link_by_ids($l['user_id'],$l['id_ancien']);
311 }
312 }
313 {
314 $page->changeTpl('fusionax/ids.tpl');
315 $missingInAX = XDB::query(
316 'SELECT COUNT(*)
317 FROM fusionax_xorg_anciens AS u
318 WHERE u.matricule_ax IS NULL');
319 if ($missingInAX)
320 {
321 $page->assign('nbMissingInAX', $missingInAX->fetchOneCell());
322 }
323 $missingInXorg = XDB::query(
324 'SELECT COUNT(*)
325 FROM fusionax_import AS i
326 WHERE i.user_id IS NULL');
327 if ($missingInXorg)
328 {
329 $page->assign(
330 'nbMissingInXorg',
331 $missingInXorg->fetchOneCell());
332 }
333 $easyToLink = FusionAxModule::find_easy_to_link(10);
334 if ($easyToLink->total() > 0)
335 {
336 $page->assign('easyToLink', $easyToLink);
337 }
338 }
339 }
340
341 function handler_misc(&$page)
342 {
343 $page->changeTpl('fusionax/misc.tpl');
344 // deceased
345 $deceasedErrorsSql = XDB::query(
346 'SELECT COUNT(*) FROM fusionax_deceased');
347 $page->assign('deceasedErrors',$deceasedErrorsSql->fetchOneCell());
348 $page->assign('deceasedMissingInXorg',XDB::iterator(
349 'SELECT
350 d.user_id,d.id_ancien,d.nom,d.prenom,d.promo,d.deces_ax,
351 CONCAT(d.prenom, " ", d.nom) AS display_name
352 FROM fusionax_deceased AS d
353 WHERE d.deces_xorg = "0000-00-00"
354 LIMIT 10'));
355 $page->assign('deceasedMissingInAX',XDB::iterator(
356 'SELECT
357 d.user_id,d.id_ancien,d.nom,d.prenom,d.promo,d.deces_xorg,
358 CONCAT(d.prenom, " ", d.nom) AS display_name
359 FROM fusionax_deceased AD d
360 WHERE d.deces_ax = "0000-00-00"
361 LIMIT 10'));
362 $page->assign('deceasedDifferent',XDB::iterator(
363 'SELECT
364 d.user_id,d.id_ancien,d.nom,d.prenom,d.promo,
365 d.deces_ax,d.deces_xorg,
366 CONCAT(d.prenom, " ", d.nom) AS display_name
367 FROM fusionax_deceased AS d
368 WHERE d.deces_xorg != "0000-00-00" AND d.deces_ax != "0000-00-00"
369 LIMIT 10'));
370 }
371 }
372
373 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:?>