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