Fixes.
[platal.git] / modules / profile / general.inc.php
1 <?php
2 /***************************************************************************
3 * Copyright (C) 2003-2009 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 ProfileSearchNames implements ProfileSetting
23 {
24 private $public_name;
25 private $private_name;
26 private $directory_name;
27 private $short_name;
28 private $sort_name;
29
30 private function matchWord($old, $new, $newLen)
31 {
32 return ($i = strpos($old, $new)) !== false
33 && ($i == 0 || $old{$i-1} == ' ')
34 && ($i + $newLen == strlen($old) || $old{$i + $newLen} == ' ');
35 }
36
37 private function prepareField($value)
38 {
39 $value = strtoupper(replace_accent($value));
40 return preg_replace('/[^A-Z]/', ' ', $value);
41 }
42
43 private function prepare(ProfilePage &$page, $field, $value, $init, &$success)
44 {
45 $success = true;
46 $ini = $this->prepareField($init);
47 $new = $this->prepareField($value);
48 $newLen = strlen($new);
49 $success = $this->matchWord($ini, $new, $newLen)
50 || ($field == 'Nom patronymique' && $new == 'DE ' . $ini);
51 if (!$success) {
52 $field = strtolower($field);
53 Platal::page()->trigError("Le " . $field . " que tu as choisi (" . $value .
54 ") est trop loin de ton " . $field . " initial (" . $init . ").");
55 }
56 return $success ? $value : $init;
57 }
58
59 public function value(ProfilePage &$page, $field, $value, &$success)
60 {
61 $success = true;
62 $success_tmp = true;
63 if (is_null($value)) {
64 $sn_all = XDB::iterator("SELECT CONCAT(sn.particle, sn.name) AS name,
65 sn.particle, sn.typeid, e.name AS type,
66 FIND_IN_SET('has_particle', e.flags) AS has_particle,
67 FIND_IN_SET('always_displayed', e.flags) AS always_displayed,
68 FIND_IN_SET('public', e.flags) AS pub
69 FROM profile_name_search AS sn
70 INNER JOIN profile_name_search_enum AS e ON (e.id = sn.typeid)
71 WHERE sn.pid = {?} AND NOT FIND_IN_SET('not_displayed', e.flags)
72 ORDER BY NOT FIND_IN_SET('always_displayed', e.flags), e.id, sn.name",
73 $page->pid());
74
75 $sn_types = XDB::iterator("SELECT id, name, FIND_IN_SET('has_particle', flags) AS has_particle
76 FROM profile_name_search_enum
77 WHERE NOT FIND_IN_SET('not_displayed', flags)
78 AND FIND_IN_SET('always_displayed', flags)
79 ORDER BY id");
80
81 $value = array();
82 $sn = $sn_all->next();
83 while ($sn_type = $sn_types->next()) {
84 if ($sn_type['id'] == $sn['typeid']) {
85 $value[] = $sn;
86 if ($sn) {
87 $sn = $sn_all->next();
88 }
89 } else {
90 $value[] = array('typeid' => $sn_type['id'],
91 'type' => $sn_type['name'],
92 'pub' => 1,
93 'has_particle' => $sn_type['has_particle'],
94 'always_displayed' => 1);
95 }
96 }
97 while ($sn) {
98 $value[] = $sn;
99 $sn = $sn_all->next();
100 }
101 } else {
102 $res = XDB::query("SELECT s.particle, s.name
103 FROM profile_name_search AS s
104 INNER JOIN profile_name_search_enum AS e ON (e.id = s.typeid)
105 WHERE s.pid = {?} AND e.name LIKE '%initial'
106 ORDER BY e.name = 'Prénom initial'",
107 $page->pid());
108 $res = $res->fetchAllAssoc();
109 $initial = array();
110 $initial['Nom patronymique'] = $res[0]['particle'] . $res[0]['name'];
111 $initial['Prénom'] = $res[1]['name'];
112 $search_names = array();
113 foreach ($value as $key => &$sn) {
114 $sn['name'] = trim($sn['name']);
115 if ($sn['type'] == 'Prénom' || $sn['type'] == 'Nom patronymique') {
116 $sn['name'] = $this->prepare($page, $sn['type'], $sn['name'],
117 $initial[$sn['type']], $success_tmp);
118 $success = $success && $success_tmp;
119 }
120 if ($sn['name'] != '') {
121 if (!isset($search_names[$sn['typeid']])) {
122 $search_names[$sn['typeid']] = array($sn['name'], $name);
123 } else {
124 $search_names[$sn['typeid']] = array_merge($search_names[$sn['typeid']], array($name));
125 }
126 }
127 }
128 require_once 'name.func.inc.php';
129 $sn_types_public = build_types('public');
130 $sn_types_private = build_types('private');
131 $full_name = build_full_name($search_names, $sn_types_public);
132 $this->directory_name = build_directory_name($search_names, $sn_types_public, $full_name);
133 $this->short_name = short_name($search_names, $sn_types_public);
134 $this->sort_name = short_name($search_names, $sn_types_public);
135 $this->public_name = build_public_name($search_names, $sn_types_public, $full_name);
136 $this->private_name = $this->public_name . build_private_name($search_names, $sn_types_private);
137 Platal::page()->assign('public_name', $this->public_name);
138 Platal::page()->assign('private_name', $this->private_name);
139 }
140 return $value;
141 }
142
143 public function save(ProfilePage &$page, $field, $value)
144 {
145 XDB::execute("DELETE FROM s
146 USING profile_name_search AS s
147 INNER JOIN profile_name_search_enum AS e ON (s.typeid = e.id)
148 WHERE s.pid = {?} AND NOT FIND_IN_SET('not_displayed', e.flags)",
149 $page->pid());
150 foreach ($value as $sn) {
151 if ($sn['name'] != '') {
152 if ($sn['particle']) {
153 list($particle, $name) = explode(' ', $sn['name'], 2);
154 $particle = trim($particle) . ' ';
155 if (!$name) {
156 list($particle, $name) = explode('\'', $sn['name'], 2);
157 $particle = trim($particle);
158 }
159 } else {
160 $particle = '';
161 $name = $sn['name'];
162 }
163 $name = trim($name);
164 XDB::execute("INSERT INTO profile_name_search (particle, name, typeid, pid)
165 VALUES ({?}, {?}, {?}, {?})",
166 $particle, $name, $sn['typeid'], $page->pid());
167 }
168 }
169 XDB::execute("UPDATE profile_display
170 SET public_name = {?}, private_name = {?},
171 directory_name = {?}, short_name = {?}, sort_name = {?}
172 WHERE pid = {?}",
173 $this->public_name, $this->private_name, $this->directory_name,
174 $this->short_name, $this->sort_name, $page->pid());
175 /*require_once('user.func.inc.php');
176 user_reindex(S::v('uid'));*/
177 }
178 }
179
180 class ProfileEdu implements ProfileSetting
181 {
182 public function __construct() {
183 }
184
185 static function sortByGradYear($line1, $line2) {
186 $a = (int) $line1['grad_year'];
187 $b = (int) $line2['grad_year'];
188 if ($a == $b) {
189 return 0;
190 }
191 return ($a < $b) ? -1 : 1;
192 }
193
194 public function value(ProfilePage &$page, $field, $value, &$success)
195 {
196 $success = true;
197 if (is_null($value) || !is_array($value)) {
198 $value = array();
199 $value = XDB::fetchAllAssoc("SELECT eduid, degreeid, fieldid, grad_year, program
200 FROM profile_education
201 WHERE uid = {?} AND !FIND_IN_SET('primary', flags)
202 ORDER BY id",
203 $page->pid());
204 } else {
205 $i = 0;
206 foreach ($value as $key=>&$edu) {
207 if (($edu['grad_year'] < 1921) || ($edu['grad_year'] > (date('Y') + 4))) {
208 Platal::page()->trigError('L\'année d\'obtention du diplôme est mal renseignée, elle doit être du type : 2004.');
209 $edu['error'] = true;
210 $success = false;
211 }
212 if ($key != $i) {
213 $value[$i] = $edu;
214 unset($value[$key]);
215 }
216 $i++;
217 }
218 usort($value, array("ProfileEdu", "sortByGradYear"));
219 }
220 return $value;
221 }
222
223 public function save(ProfilePage &$page, $field, $value)
224 {
225 XDB::execute("DELETE FROM profile_education
226 WHERE uid = {?} AND !FIND_IN_SET('primary', flags)",
227 $page->pid());
228 foreach ($value as $eduid=>&$edu) {
229 if ($edu['eduid'] != '') {
230 XDB::execute("INSERT INTO profile_education
231 SET id = {?}, uid = {?}, eduid = {?}, degreeid = {?},
232 fieldid = {?}, grad_year = {?}, program = {?}",
233 $eduid, $page->pid(), $edu['eduid'], $edu['degreeid'],
234 $edu['fieldid'], $edu['grad_year'], $edu['program']);
235 }
236 }
237 }
238 }
239
240 class ProfileEmailDirectory implements ProfileSetting
241 {
242 public function __construct(){}
243 public function save(ProfilePage &$page, $field, $value){}
244
245 public function value(ProfilePage &$page, $field, $value, &$success)
246 {
247 $p = Platal::page();
248
249 $success = true;
250 if (!is_null($value)) {
251 $email_stripped = strtolower(trim($value));
252 if ((!isvalid_email($email_stripped)) && ($email_stripped) && ($page->values['email_directory'] == "new@example.org")) {
253 $p->assign('email_error', '1');
254 $p->assign('email_directory_error', $email_stripped);
255 $p->trigError('Adresse Email invalide');
256 $success = false;
257 } else {
258 $p->assign('email_error', '0');
259 }
260 }
261 return $value;
262 }
263 }
264
265 class ProfileNetworking implements ProfileSetting
266 {
267 private $email;
268 private $pub;
269 private $web;
270 private $number;
271
272 public function __construct()
273 {
274 $this->email = new ProfileEmail();
275 $this->pub = new ProfilePub();
276 $this->web = new ProfileWeb();
277 $this->number = new ProfileNumber();
278 }
279
280 public function value(ProfilePage &$page, $field, $value, &$success)
281 {
282 if (is_null($value)) {
283 $value = XDB::fetchAllAssoc("SELECT n.address, n.network_type AS type, n.pub, m.name
284 FROM profile_networking AS n
285 INNER JOIN profile_networking_enum AS m ON (n.network_type = m.network_type)
286 WHERE n.uid = {?}",
287 $page->pid());
288 }
289 if (!is_array($value)) {
290 $value = array();
291 }
292 $filters = XDB::fetchAllAssoc('type', 'SELECT filter, network_type AS type
293 FROM profile_networking_enum;');
294 $success = true;
295 foreach($value as $i=>&$network) {
296 if (!trim($network['address'])) {
297 unset($value[$i]);
298 } else {
299 if (!isset($network['pub'])) {
300 $network['pub'] = 'private';
301 }
302 $network['error'] = false;
303 $network['pub'] = $this->pub->value($page, 'pub', $network['pub'], $s);
304 $s = true;
305 if ($filters[$network['type']] == 'web') {
306 $network['address'] = $this->web->value($page, 'address', $network['address'], $s);
307 } elseif ($filters[$network['type']] == 'email') {
308 $network['address'] = $this->email->value($page, 'address', $network['address'], $s);
309 } elseif ($filters[$network['type']] == 'number') {
310 $network['address'] = $this->number->value($page, 'address', $network['address'], $s);
311 }
312 if (!$s) {
313 $success = false;
314 $network['error'] = true;
315 }
316 }
317 }
318 return $value;
319 }
320
321 public function save(ProfilePage &$page, $field, $value)
322 {
323 XDB::execute("DELETE FROM profile_networking
324 WHERE uid = {?}",
325 $page->pid());
326 if (!count($value)) {
327 return;
328 }
329 $insert = array();
330 foreach ($value as $id=>$network) {
331 XDB::execute("INSERT INTO profile_networking (uid, nwid, network_type, address, pub)
332 VALUES ({?}, {?}, {?}, {?}, {?})",
333 $page->pid(), $id, $network['type'], $network['address'], $network['pub']);
334 }
335 }
336 }
337
338 class ProfileGeneral extends ProfilePage
339 {
340 protected $pg_template = 'profile/general.tpl';
341
342 public function __construct(PlWizard &$wiz)
343 {
344 parent::__construct($wiz);
345 $this->settings['search_names']
346 = new ProfileSearchNames();
347 $this->settings['birthdate'] = new ProfileDate();
348 $this->settings['freetext_pub']
349 = $this->settings['photo_pub']
350 = new ProfilePub();
351 $this->settings['freetext']
352 = $this->settings['nationality1']
353 = $this->settings['nationality2']
354 = $this->settings['nationality3']
355 = $this->settings['yourself']
356 = $this->settings['promo']
357 = null;
358 $this->settings['synchro_ax']
359 = new ProfileBool();
360 $this->settings['email_directory']
361 = new ProfileEmail();
362 $this->settings['email_directory_new']
363 = new ProfileEmailDirectory();
364 $this->settings['networking'] = new ProfileNetworking();
365 $this->settings['tels'] = new ProfilePhones('user', 0);
366 $this->settings['edus'] = new ProfileEdu();
367 $this->watched= array('freetext' => true, 'tels' => true,
368 'networking' => true, 'edus' => true,
369 'nationality1' => true, 'nationality2' => true,
370 'nationality3' => true, 'search_names' => true);
371 }
372
373 protected function _fetchData()
374 {
375 // Checkout all data...
376 $res = XDB::query("SELECT p.promo, e.entry_year AS entry_year, e.grad_year AS grad_year,
377 pr.nationality1, pr.nationality2, pr.nationality3, pr.birthdate,
378 t.display_tel as mobile, t.pub as mobile_pub,
379 d.email_directory as email_directory,
380 pr.freetext, pr.freetext_pub as freetext_pub
381 FROM profiles AS pr
382 INNER JOIN profile_display AS p ON (p.pid = pr.pid)
383 INNER JOIN profile_education AS e ON (e.uid = pr.pid AND FIND_IN_SET('primary', e.flags))
384 LEFT JOIN profile_phones AS t ON (t.uid = pr.pid AND link_type = 'user')
385 LEFT JOIN profile_directory AS d ON (d.uid = pr.pid)
386 WHERE pr.pid = {?}", $this->pid());
387 $this->values = $res->fetchOneAssoc();
388 if ($this->owner) {
389 $this->values['yourself'] = $this->owner->displayName();
390 }
391
392 // Retreive photo informations
393 $res = XDB::query("SELECT pub
394 FROM photo
395 WHERE uid = {?}", $this->pid());
396 $this->values['photo_pub'] = $res->fetchOneCell();
397
398 if ($this->owner) {
399 $res = XDB::query("SELECT COUNT(*)
400 FROM requests
401 WHERE type='photo' AND user_id = {?}",
402 $this->owner->id());
403 $this->values['nouvellephoto'] = $res->fetchOneCell();
404 } else {
405 $this->values['nouvellephoto'] = 0;
406 }
407
408 // Proposes choice for promotion
409 if ($this->values['entry_year'] != $this->values['grad_year'] - 3) {
410 for ($i = $this->values['entry_year']; $i < $this->values['grad_year'] - 2; $i++) {
411 $this->values['promo_choice'][] = "X" . $i;
412 }
413 }
414 }
415
416 protected function _saveData()
417 {
418 if ($this->changed['nationality1'] || $this->changed['nationality2'] || $this->changed['nationality3']
419 || $this->changed['birthdate'] || $this->changed['freetext'] || $this->changed['freetext_pub']) {
420 if ($this->values['nationality3'] == "") {
421 $this->values['nationality3'] = NULL;
422 }
423 if ($this->values['nationality2'] == "") {
424 $this->values['nationality2'] = $this->values['nationality3'];
425 $this->values['nationality3'] = NULL;
426 }
427 if ($this->values['nationality1'] == "") {
428 $this->values['nationality1'] = $this->values['nationality2'];
429 $this->values['nationality2'] = $this->values['nationality3'];
430 $this->values['nationality3'] = NULL;
431 }
432
433 XDB::execute("UPDATE profiles
434 SET nationality1 = {?}, nationality2 = {?}, nationality3 = {?}, birthdate = {?},
435 freetext = {?}, freetext_pub = {?}
436 WHERE user_id = {?}",
437 $this->values['nationality1'], $this->values['nationality2'], $this->values['nationality3'],
438 preg_replace('@(\d{2})/(\d{2})/(\d{4})@', '\3-\2-\1', $this->values['birthdate']),
439 $this->values['freetext'], $this->values['freetext_pub'],
440 $this->pid());
441 }
442 if ($this->changed['email_directory']) {
443 $new_email = ($this->values['email_directory'] == "new@example.org") ?
444 $this->values['email_directory_new'] : $this->values['email_directory'];
445 if ($new_email == "") {
446 $new_email = NULL;
447 }
448 XDB::execute("REPLACE INTO profile_directory (uid, email_directory)
449 VALUES ({?}, {?})",
450 $this->pid(), $new_email);
451 }
452 if ($this->changed['photo_pub']) {
453 XDB::execute("UPDATE photo
454 SET pub = {?}
455 WHERE uid = {?}",
456 $this->values['photo_pub'], $this->pid());
457 }
458 if ($this->changed['yourself']) {
459 XDB::execute('UPDATE accounts
460 SET display_name = {?}
461 WHERE pid = {?}', $this->pid());
462 }
463 if ($this->changed['promo']) {
464 XDB::execute("UPDATE profile_display
465 SET promo = {?}
466 WHERE pid = {?}",
467 $this->values['promo'], $this->pid());
468 }
469 }
470
471 public function _prepare(PlPage &$page, $id)
472 {
473 require_once "education.func.inc.php";
474
475 $res = XDB::query("SELECT id, field
476 FROM profile_education_field_enum
477 ORDER BY field");
478 $page->assign('edu_fields', $res->fetchAllAssoc());
479
480 require_once "emails.combobox.inc.php";
481 fill_email_combobox($page, $this->owner, $this->profile);
482
483 $res = XDB::query("SELECT nw.network_type AS type, nw.name
484 FROM profile_networking_enum AS nw
485 ORDER BY name");
486 $page->assign('network_list', $res->fetchAllAssoc());
487
488 $res = XDB::query("SELECT public_name, private_name
489 FROM profile_display
490 WHERE pid = {?}",
491 $this->pid());
492 $res = $res->fetchOneRow();
493 $page->assign('public_name', $res[0]);
494 $page->assign('private_name', $res[1]);
495 }
496 }
497
498 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
499 ?>