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