]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Core/Preferences.php
8b53e5bd038ba2546829b015fc99e83c8d3428a5
[galette.git] / galette / lib / Galette / Core / Preferences.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Preferences handling
7 *
8 * PHP version 5
9 *
10 * Copyright © 2007-2014 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Core
28 * @package Galette
29 * @author Johan Cwiklinski <johan@x-tnd.be>
30 * @copyright 2007-2014 The Galette Team
31 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
32 * @link http://galette.tuxfamily.org
33 * @since Available since 0.7dev - 2007-10-14
34 */
35
36 namespace Galette\Core;
37
38 use Throwable;
39 use Analog\Analog;
40 use Galette\Entity\Adherent;
41 use Galette\Entity\Status;
42 use Galette\Core\Db;
43 use Galette\IO\PdfMembersCards;
44 use Galette\Repository\Members;
45
46 /**
47 * Preferences for galette
48 *
49 * @category Core
50 * @name Preferences
51 * @package Galette
52 * @author Johan Cwiklinski <johan@x-tnd.be>
53 * @copyright 2007-2014 The Galette Team
54 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
55 * @link http://galette.tuxfamily.org
56 * @since Available since 0.7dev - 2007-10-14
57 *
58 * @property string $pref_admin_login Super admin login
59 * @property string $pref_admin_pass Super admin password
60 * @property string $pref_nom Association name
61 * @property string $pref_slogan Association slogan
62 * @property string $pref_adresse Address
63 * @property string $pref_adresse2 Address continuation
64 * @property string $pref_cp Association zipcode
65 * @property string $pref_ville Association town
66 * @property string $pref_pays Country
67 * @property integer $pref_postal_adress Postal adress to use, one of self::POSTAL_ADDRESS*
68 * @property integer $pref_postal_staff_member Staff member ID from which retrieve postal address
69 * @property string $pref_lang Default instance language
70 * @property integer $pref_numrows Default number of rows in lists
71 * @property integer $pref_log History, one of self::LOG_*
72 * @property interger $pref_statut Default status for new members
73 * @property string $pref_email_nom
74 * @property string $pref_email
75 * @property string $pref_email_newadh
76 * @property boolean $pref_bool_mailadh
77 * @property boolean $pref_editor_enabled
78 * @property integer $pref_mail_method Mail method, see GaletteMail::METHOD_*
79 * @property string $pref_mail_smtp
80 * @property string $pref_mail_smtp_host
81 * @property boolean $pref_mail_smtp_auth
82 * @property boolean $pref_mail_smtp_secure
83 * @property integer $pref_mail_smtp_port
84 * @property string $pref_mail_smtp_user
85 * @property string $pref_mail_smtp_password
86 * @property integer $pref_membership_ext
87 * @property string $pref_beg_membership
88 * @property integer $pref_membership_offermonths
89 * @property string $pref_email_reply_to
90 * @property string $pref_website
91 * @property integer $pref_etiq_marges_v
92 * @property string $pref_etiq_marges_h
93 * @property string $pref_etiq_hspace
94 * @property string $pref_etiq_vspace
95 * @property string $pref_etiq_hsize
96 * @property string $pref_etiq_vsize
97 * @property string $pref_etiq_cols
98 * @property string $pref_etiq_rows
99 * @property string $pref_etiq_corps
100 * @property string $pref_card_abrev
101 * @property string $pref_card_strip
102 * @property string $pref_card_tcol
103 * @property string $pref_card_scol
104 * @property string $pref_card_bcol
105 * @property string $pref_card_hcol
106 * @property string $pref_bool_display_title
107 * @property integer $pref_card_address
108 * @property string $pref_card_year
109 * @property integer $pref_card_marges_v
110 * @property integer $pref_card_marges_h
111 * @property integer $pref_card_vspace
112 * @property integer $pref_card_hspace
113 * @property string $pref_card_self
114 * @property string $pref_theme Prefered theme
115 * @property boolean $pref_bool_publicpages
116 * @property integer $pref_publicpages_visibility
117 * @property boolean $pref_bool_selfsubscribe
118 * @property string $pref_googleplus
119 * @property string $pref_facebook
120 * @property string $pref_twitter
121 * @property string $pref_viadeo
122 * @property string $pref_linkedin
123 * @property string $pref_mail_sign
124 * @property string $pref_new_contrib_script
125 * @property boolean $pref_bool_wrap_mails
126 * @property string $pref_rss_url
127 * @property boolean $pref_show_id
128 * @property string $pref_adhesion_form
129 * @property boolean $pref_mail_allow_unsecure
130 * @property string $pref_instance_uuid
131 * @property string $pref_registration_uuid
132 * @property string $pref_telemetry_date
133 * @property string $pref_registration_date
134 * @property string $pref_footer
135 * @property integer $pref_filter_account
136 * @property string $pref_galette_url
137 * @property integer $pref_redirect_on_create
138 * @property integer $pref_password_length
139 * @property boolean $pref_password_blacklist
140 * @property integer $pref_password_strength
141 * @property-read string $vpref_email_newadh Comma separated list of mail senders
142 */
143 class Preferences
144 {
145 private $zdb;
146 private $prefs;
147 private $errors = [];
148
149 public const TABLE = 'preferences';
150 public const PK = 'nom_pref';
151
152 /** Postal address will be the one given in the preferences */
153 public const POSTAL_ADDRESS_FROM_PREFS = 0;
154 /** Postal address will be the one of the selected staff member */
155 public const POSTAL_ADDRESS_FROM_STAFF = 1;
156
157 /** Public pages stuff */
158 /** Public pages are publically visibles */
159 public const PUBLIC_PAGES_VISIBILITY_PUBLIC = 0;
160 /** Public pages are visibles for up to date members only */
161 public const PUBLIC_PAGES_VISIBILITY_RESTRICTED = 1;
162 /** Public pages are visibles for admin and staff members only */
163 public const PUBLIC_PAGES_VISIBILITY_PRIVATE = 2;
164
165 public const LOG_DISABLED = 0;
166 public const LOG_ENABLED = 1;
167
168 /** No password strength */
169 public const PWD_NONE = 0;
170 /** Weak password strength */
171 public const PWD_WEAK = 1;
172 /** Medium password strength */
173 public const PWD_MEDIUM = 2;
174 /** Strong password strength */
175 public const PWD_STRONG = 3;
176 /** Very strong password strength */
177 public const PWD_VERY_STRONG = 4;
178
179 private static $fields = array(
180 'nom_pref',
181 'val_pref'
182 );
183
184 private static $defaults = array(
185 'pref_admin_login' => 'admin',
186 'pref_admin_pass' => 'admin',
187 'pref_nom' => 'Galette',
188 'pref_slogan' => '',
189 'pref_adresse' => '-',
190 'pref_adresse2' => '',
191 'pref_cp' => '',
192 'pref_ville' => '',
193 'pref_pays' => '',
194 'pref_postal_adress' => self::POSTAL_ADDRESS_FROM_PREFS,
195 'pref_postal_staff_member' => '',
196 'pref_lang' => I18n::DEFAULT_LANG,
197 'pref_numrows' => 30,
198 'pref_log' => self::LOG_ENABLED,
199 'pref_statut' => Status::DEFAULT_STATUS,
200 /* Preferences for emails */
201 'pref_email_nom' => 'Galette',
202 'pref_email' => 'mail@domain.com',
203 'pref_email_newadh' => 'mail@domain.com',
204 'pref_bool_mailadh' => false,
205 'pref_editor_enabled' => false,
206 'pref_mail_method' => GaletteMail::METHOD_DISABLED,
207 'pref_mail_smtp' => '',
208 'pref_mail_smtp_host' => '',
209 'pref_mail_smtp_auth' => false,
210 'pref_mail_smtp_secure' => false,
211 'pref_mail_smtp_port' => '',
212 'pref_mail_smtp_user' => '',
213 'pref_mail_smtp_password' => '',
214 'pref_membership_ext' => 12,
215 'pref_beg_membership' => '',
216 'pref_membership_offermonths' => 0,
217 'pref_email_reply_to' => '',
218 'pref_website' => '',
219 /* Preferences for labels */
220 'pref_etiq_marges_v' => 10,
221 'pref_etiq_marges_h' => 10,
222 'pref_etiq_hspace' => 10,
223 'pref_etiq_vspace' => 5,
224 'pref_etiq_hsize' => 90,
225 'pref_etiq_vsize' => 35,
226 'pref_etiq_cols' => 2,
227 'pref_etiq_rows' => 7,
228 'pref_etiq_corps' => 12,
229 /* Preferences for members cards */
230 'pref_card_abrev' => 'GALETTE',
231 'pref_card_strip' => 'Gestion d\'Adherents en Ligne Extrêmement Tarabiscotée',
232 'pref_card_tcol' => '#FFFFFF',
233 'pref_card_scol' => '#8C2453',
234 'pref_card_bcol' => '#53248C',
235 'pref_card_hcol' => '#248C53',
236 'pref_bool_display_title' => false,
237 'pref_card_address' => 1,
238 'pref_card_year' => '',
239 'pref_card_marges_v' => 15,
240 'pref_card_marges_h' => 20,
241 'pref_card_vspace' => 5,
242 'pref_card_hspace' => 10,
243 'pref_card_self' => 1,
244 'pref_theme' => 'default',
245 'pref_bool_publicpages' => true,
246 'pref_publicpages_visibility' => self::PUBLIC_PAGES_VISIBILITY_RESTRICTED,
247 'pref_bool_selfsubscribe' => true,
248 'pref_googleplus' => '',
249 'pref_facebook' => '',
250 'pref_twitter' => '',
251 'pref_viadeo' => '',
252 'pref_linkedin' => '',
253 'pref_mail_sign' => "{NAME}\r\n\r\n{WEBSITE}\r\n{GOOGLEPLUS}\r\n{FACEBOOK}\r\n{TWITTER}\r\n{LINKEDIN}\r\n{VIADEO}",
254 /* New contribution script */
255 'pref_new_contrib_script' => '',
256 'pref_bool_wrap_mails' => true,
257 'pref_rss_url' => 'http://galette.eu/dc/index.php/feed/atom',
258 'pref_show_id' => false,
259 'pref_adhesion_form' => '\Galette\IO\PdfAdhesionForm',
260 'pref_mail_allow_unsecure' => false,
261 'pref_instance_uuid' => '',
262 'pref_registration_uuid' => '',
263 'pref_telemetry_date' => '',
264 'pref_registration_date' => '',
265 'pref_footer' => '',
266 'pref_filter_account' => Members::ALL_ACCOUNTS,
267 'pref_galette_url' => '',
268 'pref_redirect_on_create' => Adherent::AFTER_ADD_DEFAULT,
269 /* Security related */
270 'pref_password_length' => 6,
271 'pref_password_blacklist' => false,
272 'pref_password_strength' => self::PWD_NONE
273 );
274
275 // flagging required fields
276 private $required = array(
277 'pref_nom',
278 'pref_lang',
279 'pref_numrows',
280 'pref_log',
281 'pref_etiq_marges_v',
282 'pref_etiq_marges_h',
283 'pref_etiq_hspace',
284 'pref_etiq_vspace',
285 'pref_etiq_hsize',
286 'pref_etiq_vsize',
287 'pref_etiq_cols',
288 'pref_etiq_rows',
289 'pref_etiq_corps',
290 'pref_card_abrev',
291 'pref_card_strip',
292 'pref_card_marges_v',
293 'pref_card_marges_h',
294 'pref_card_hspace',
295 'pref_card_vspace'
296 );
297
298 /**
299 * Default constructor
300 *
301 * @param Db $zdb Db instance
302 * @param boolean $load Automatically load preferences on load
303 *
304 * @return void
305 */
306 public function __construct(Db $zdb, $load = true)
307 {
308 $this->zdb = $zdb;
309 if ($load) {
310 $this->load();
311 $this->checkUpdate();
312 }
313 }
314
315 /**
316 * Check if all fields referenced in the default array does exists,
317 * create them if not
318 *
319 * @return void
320 */
321 private function checkUpdate()
322 {
323 $proceed = false;
324 $params = array();
325 foreach (self::$defaults as $k => $v) {
326 if (!isset($this->prefs[$k])) {
327 $this->prefs[$k] = $v;
328 Analog::log(
329 'The field `' . $k . '` does not exists, Galette will attempt to create it.',
330 Analog::INFO
331 );
332 $proceed = true;
333 $params[] = array(
334 'nom_pref' => $k,
335 'val_pref' => $v
336 );
337 }
338 }
339 if ($proceed !== false) {
340 try {
341 $insert = $this->zdb->insert(self::TABLE);
342 $insert->values(
343 array(
344 'nom_pref' => ':nom_pref',
345 'val_pref' => ':val_pref'
346 )
347 );
348 $stmt = $this->zdb->sql->prepareStatementForSqlObject($insert);
349
350 foreach ($params as $p) {
351 $stmt->execute(
352 array(
353 'nom_pref' => $p['nom_pref'],
354 'val_pref' => $p['val_pref']
355 )
356 );
357 }
358 } catch (Throwable $e) {
359 Analog::log(
360 'Unable to add missing preferences.' . $e->getMessage(),
361 Analog::WARNING
362 );
363 return false;
364 }
365
366 Analog::log(
367 'Missing preferences were successfully stored into database.',
368 Analog::INFO
369 );
370 }
371 }
372
373 /**
374 * Load current preferences from database.
375 *
376 * @return boolean
377 */
378 public function load()
379 {
380 $this->prefs = array();
381
382 try {
383 $result = $this->zdb->selectAll(self::TABLE);
384 foreach ($result as $pref) {
385 $this->prefs[$pref->nom_pref] = $pref->val_pref;
386 }
387 return true;
388 } catch (Throwable $e) {
389 Analog::log(
390 'Preferences cannot be loaded. Galette should not work without ' .
391 'preferences. Exiting.',
392 Analog::URGENT
393 );
394 return false;
395 }
396 }
397
398 /**
399 * Set default preferences at install time
400 *
401 * @param string $lang language selected at install screen
402 * @param string $adm_login admin login entered at install time
403 * @param string $adm_pass admin password entered at install time
404 *
405 * @return boolean|\Exception
406 */
407 public function installInit($lang, $adm_login, $adm_pass)
408 {
409 try {
410 //first, we drop all values
411 $delete = $this->zdb->delete(self::TABLE);
412 $this->zdb->execute($delete);
413
414 //we then replace default values with the ones user has selected
415 $values = self::$defaults;
416 $values['pref_lang'] = $lang;
417 $values['pref_admin_login'] = $adm_login;
418 $values['pref_admin_pass'] = $adm_pass;
419 $values['pref_card_year'] = date('Y');
420
421 $insert = $this->zdb->insert(self::TABLE);
422 $insert->values(
423 array(
424 'nom_pref' => ':nom_pref',
425 'val_pref' => ':val_pref'
426 )
427 );
428 $stmt = $this->zdb->sql->prepareStatementForSqlObject($insert);
429
430 foreach ($values as $k => $v) {
431 $stmt->execute(
432 array(
433 'nom_pref' => $k,
434 'val_pref' => $v
435 )
436 );
437 }
438
439 Analog::log(
440 'Default preferences were successfully stored into database.',
441 Analog::INFO
442 );
443 return true;
444 } catch (Throwable $e) {
445 Analog::log(
446 'Unable to initialize default preferences.' . $e->getMessage(),
447 Analog::WARNING
448 );
449 throw $e;
450 }
451 }
452
453 /**
454 * Returns all preferences keys
455 *
456 * @return array
457 */
458 public function getFieldsNames()
459 {
460 return array_keys($this->prefs);
461 }
462
463 /**
464 * Check values
465 *
466 * @param array $values Values
467 * @param Login $login Logged in user
468 *
469 * @return boolean
470 */
471 public function check(array $values, Login $login)
472 {
473 $insert_values = array();
474 if ($login->isSuperAdmin() && GALETTE_MODE !== 'DEMO') {
475 $this->required[] = 'pref_admin_login';
476 }
477
478 // obtain fields
479 foreach ($this->getFieldsNames() as $fieldname) {
480 if (isset($values[$fieldname])) {
481 $value = trim($values[$fieldname]);
482 } else {
483 $value = "";
484 }
485
486 $insert_values[$fieldname] = $value;
487 }
488
489 // missing relations
490 if (
491 GALETTE_MODE !== 'DEMO'
492 && isset($insert_values['pref_mail_method'])
493 ) {
494 if ($insert_values['pref_mail_method'] > GaletteMail::METHOD_DISABLED) {
495 if (
496 !isset($insert_values['pref_email_nom'])
497 || $insert_values['pref_email_nom'] == ''
498 ) {
499 $this->errors[] = _T("- You must indicate a sender name for emails!");
500 }
501 if (
502 !isset($insert_values['pref_email'])
503 || $insert_values['pref_email'] == ''
504 ) {
505 $this->errors[] = _T("- You must indicate an email address Galette should use to send emails!");
506 }
507 if ($insert_values['pref_mail_method'] == GaletteMail::METHOD_SMTP) {
508 if (
509 !isset($insert_values['pref_mail_smtp_host'])
510 || $insert_values['pref_mail_smtp_host'] == ''
511 ) {
512 $this->errors[] = _T("- You must indicate the SMTP server you want to use!");
513 }
514 }
515 if (
516 $insert_values['pref_mail_method'] == GaletteMail::METHOD_GMAIL
517 || ($insert_values['pref_mail_method'] == GaletteMail::METHOD_SMTP
518 && $insert_values['pref_mail_smtp_auth'])
519 ) {
520 if (
521 !isset($insert_values['pref_mail_smtp_user'])
522 || trim($insert_values['pref_mail_smtp_user']) == ''
523 ) {
524 $this->errors[] = _T("- You must provide a login for SMTP authentication.");
525 }
526 if (
527 !isset($insert_values['pref_mail_smtp_password'])
528 || ($insert_values['pref_mail_smtp_password']) == ''
529 ) {
530 $this->errors[] = _T("- You must provide a password for SMTP authentication.");
531 }
532 }
533 }
534 }
535
536 if (
537 isset($insert_values['pref_beg_membership'])
538 && $insert_values['pref_beg_membership'] != ''
539 && isset($insert_values['pref_membership_ext'])
540 && $insert_values['pref_membership_ext'] != ''
541 ) {
542 $this->errors[] = _T("- Default membership extention and beginning of membership are mutually exclusive.");
543 }
544
545 if (
546 isset($insert_values['pref_membership_offermonths'])
547 && (int)$insert_values['pref_membership_offermonths'] > 0
548 && isset($insert_values['pref_membership_ext'])
549 && $insert_values['pref_membership_ext'] != ''
550 ) {
551 $this->errors[] = _T("- Offering months is only compatible with beginning of membership.");
552 }
553
554 // missing required fields?
555 foreach ($this->required as $val) {
556 if (!isset($values[$val]) || isset($values[$val]) && trim($values[$val]) == '') {
557 $this->errors[] = str_replace(
558 '%field',
559 $val,
560 _T("- Mandatory field %field empty.")
561 );
562 }
563 }
564
565 if (GALETTE_MODE !== 'DEMO' && isset($values['pref_admin_pass_check'])) {
566 // Check passwords. Hash will be done into the Preferences class
567 if (strcmp($insert_values['pref_admin_pass'], $values['pref_admin_pass_check']) != 0) {
568 $this->errors[] = _T("Passwords mismatch");
569 }
570 }
571
572 //postal address
573 if (isset($insert_values['pref_postal_adress'])) {
574 $value = $insert_values['pref_postal_adress'];
575 if ($value == Preferences::POSTAL_ADDRESS_FROM_PREFS) {
576 if (isset($insert_values['pref_postal_staff_member'])) {
577 unset($insert_values['pref_postal_staff_member']);
578 }
579 } elseif ($value == Preferences::POSTAL_ADDRESS_FROM_STAFF) {
580 if (!isset($value) || $value < 1) {
581 $this->errors[] = _T("You have to select a staff member");
582 }
583 }
584 }
585
586 // update preferences
587 foreach ($insert_values as $champ => $valeur) {
588 if (
589 $login->isSuperAdmin()
590 || (!$login->isSuperAdmin()
591 && ($champ != 'pref_admin_pass' && $champ != 'pref_admin_login'))
592 ) {
593 if (
594 ($champ == "pref_admin_pass" && $_POST['pref_admin_pass'] != '')
595 || ($champ != "pref_admin_pass")
596 ) {
597 $this->$champ = $valeur;
598 }
599 }
600 }
601
602 return 0 === count($this->errors);
603 }
604
605 /**
606 * Validate value of a field
607 *
608 * @param string $fieldname Field name
609 * @param mixed $value Value to be set
610 *
611 * @return mixed
612 */
613 public function validateValue($fieldname, $value)
614 {
615 global $login;
616
617 switch ($fieldname) {
618 case 'pref_email':
619 case 'pref_email_newadh':
620 case 'pref_email_reply_to':
621 //check emails validity
622 //may be a comma separated list of valid emails identifiers:
623 //"The Name <mail@domain.com>,The Other <other@mail.com>" expect for reply_to.
624 $addresses = [];
625 if (trim($value) != '') {
626 if ($fieldname == 'pref_email_newadh') {
627 $addresses = explode(',', $value);
628 } else {
629 $addresses = [$value];
630 }
631 }
632 foreach ($addresses as $address) {
633 if (!GaletteMail::isValidEmail($address)) {
634 $msg = str_replace('%s', $address, _T("Invalid E-Mail address: %s"));
635 Analog::log($msg, Analog::WARNING);
636 $this->errors[] = $msg;
637 }
638 }
639 break;
640 case 'pref_admin_login':
641 if (GALETTE_MODE === 'DEMO') {
642 Analog::log(
643 'Trying to set superadmin login while in DEMO.',
644 Analog::WARNING
645 );
646 } else {
647 if (strlen($value) < 4) {
648 $this->errors[] = _T("- The username must be composed of at least 4 characters!");
649 } else {
650 //check if login is already taken
651 if ($login->loginExists($value)) {
652 $this->errors[] = _T("- This username is already used by another member !");
653 }
654 }
655 }
656 break;
657 case 'pref_numrows':
658 if (!is_numeric($value) || $value < 0) {
659 $this->errors[] = _T("- The numbers and measures have to be integers!");
660 }
661 break;
662 case 'pref_etiq_marges_h':
663 case 'pref_etiq_marges_v':
664 case 'pref_etiq_hspace':
665 case 'pref_etiq_vspace':
666 case 'pref_etiq_hsize':
667 case 'pref_etiq_vsize':
668 case 'pref_etiq_cols':
669 case 'pref_etiq_rows':
670 case 'pref_etiq_corps':
671 case 'pref_card_marges_v':
672 case 'pref_card_marges_h':
673 case 'pref_card_hspace':
674 case 'pref_card_vspace':
675 // prevent division by zero
676 if ($fieldname == 'pref_numrows' && $value == '0') {
677 $value = '10';
678 }
679 if (!is_numeric($value) || $value < 0) {
680 $this->errors[] = _T("- The numbers and measures have to be integers!");
681 }
682 break;
683 case 'pref_card_tcol':
684 case 'pref_card_scol':
685 case 'pref_card_bcol':
686 case 'pref_card_hcol':
687 $matches = [];
688 if (!preg_match("/^(#)?([0-9A-F]{6})$/i", $value, $matches)) {
689 // Set strip background colors to black or white (for tcol)
690 $value = ($fieldname == 'pref_card_tcol' ? '#FFFFFF' : '#000000');
691 } else {
692 $value = '#' . $matches[2];
693 }
694 break;
695 case 'pref_admin_pass':
696 if (GALETTE_MODE == 'DEMO') {
697 Analog::log(
698 'Trying to set superadmin pass while in DEMO.',
699 Analog::WARNING
700 );
701 } else {
702 $pwcheck = new \Galette\Util\Password($this);
703 $pwcheck->addPersonalInformation(['pref_admin_login' => $this->pref_admin_login]);
704 if (!$pwcheck->isValid($value)) {
705 $this->errors = array_merge(
706 $this->errors,
707 $pwcheck->getErrors()
708 );
709 }
710 }
711 break;
712 case 'pref_membership_ext':
713 if (!is_numeric($value) || $value < 0) {
714 $this->errors[] = _T("- Invalid number of months of membership extension.");
715 }
716 break;
717 case 'pref_beg_membership':
718 $beg_membership = explode("/", $value);
719 if (count($beg_membership) != 2) {
720 $this->errors[] = _T("- Invalid format of beginning of membership.");
721 } else {
722 $now = getdate();
723 if (!checkdate($beg_membership[1], $beg_membership[0], $now['year'])) {
724 $this->errors[] = _T("- Invalid date for beginning of membership.");
725 }
726 }
727 break;
728 case 'pref_membership_offermonths':
729 if (!is_numeric($value) || $value < 0) {
730 $this->errors[] = _T("- Invalid number of offered months.");
731 }
732 break;
733 case 'pref_card_year':
734 if ($value !== 'DEADLINE' && !preg_match('/^(?:\d{4}|\d{2})(\D?)(?:\d{4}|\d{2})$/', $value)) {
735 $this->errors[] = _T("- Invalid year for cards.");
736 }
737 break;
738 }
739
740 return $value;
741 }
742
743 /**
744 * Will store all preferences in the database
745 *
746 * @return boolean
747 */
748 public function store()
749 {
750 try {
751 $this->zdb->connection->beginTransaction();
752 $update = $this->zdb->update(self::TABLE);
753 $update->set(
754 array(
755 'val_pref' => ':val_pref'
756 )
757 )->where->equalTo('nom_pref', ':nom_pref');
758
759 $stmt = $this->zdb->sql->prepareStatementForSqlObject($update);
760
761 foreach (self::$defaults as $k => $v) {
762 if (
763 GALETTE_MODE == 'DEMO'
764 && in_array($k, ['pref_admin_pass', 'pref_admin_login', 'pref_mail_method'])
765 ) {
766 continue;
767 }
768 Analog::log('Storing ' . $k, Analog::DEBUG);
769
770 $value = $this->prefs[$k];
771 //do not store pdf_adhesion_form, it's designed to be overriden by plugin
772 if ($k === 'pref_adhesion_form') {
773 if (trim($v) == '') {
774 //Reset to default, should not be empty
775 $v = self::$defaults['pref_adhesion_form'];
776 }
777 $value = $v;
778 }
779
780 $stmt->execute(
781 array(
782 'val_pref' => $value,
783 'nom_pref' => $k
784 )
785 );
786 }
787 $this->zdb->connection->commit();
788 Analog::log(
789 'Preferences were successfully stored into database.',
790 Analog::INFO
791 );
792 return true;
793 } catch (Throwable $e) {
794 $this->zdb->connection->rollBack();
795
796 $messages = array();
797 do {
798 $messages[] = $e->getMessage();
799 } while ($e = $e->getPrevious());
800
801 Analog::log(
802 'Unable to store preferences | ' . print_r($messages, true),
803 Analog::WARNING
804 );
805 return false;
806 }
807 }
808
809 /**
810 * Returns postal address
811 *
812 * @return string postal address
813 */
814 public function getPostalAddress()
815 {
816 $regs = array(
817 '/%name/',
818 '/%complement/',
819 '/%address/',
820 '/%zip/',
821 '/%town/',
822 '/%country/',
823 );
824
825 $replacements = null;
826
827 if ($this->prefs['pref_postal_adress'] == self::POSTAL_ADDRESS_FROM_PREFS) {
828 $_address = $this->prefs['pref_adresse'];
829 if ($this->prefs['pref_adresse2'] && $this->prefs['pref_adresse2'] != '') {
830 $_address .= "\n" . $this->prefs['pref_adresse2'];
831 }
832 $replacements = array(
833 $this->prefs['pref_nom'],
834 "\n",
835 $_address,
836 $this->prefs['pref_cp'],
837 $this->prefs['pref_ville'],
838 $this->prefs['pref_pays']
839 );
840 } else {
841 //get selected staff member address
842 $adh = new Adherent($this->zdb, (int)$this->prefs['pref_postal_staff_member']);
843 $_complement = preg_replace(
844 array('/%name/', '/%status/'),
845 array($this->prefs['pref_nom'], $adh->sstatus),
846 _T("%name association's %status")
847 ) . "\n";
848 $_address = $adh->address;
849 if ($adh->address_continuation && $adh->address_continuation != '') {
850 $_address .= "\n" . $adh->address_continuation;
851 }
852 $replacements = array(
853 $adh->sfullname . "\n",
854 $_complement,
855 $_address,
856 $adh->zipcode,
857 $adh->town,
858 $adh->country
859 );
860 }
861
862 /*FIXME: i18n fails :/ */
863 /*$r = preg_replace(
864 $regs,
865 $replacements,
866 _T("%name\n%complement\n%address\n%zip %town - %country")
867 );*/
868 $r = preg_replace(
869 $regs,
870 $replacements,
871 "%name%complement%address\n%zip %town - %country"
872 );
873 return $r;
874 }
875
876 /**
877 * Are public pages visibles?
878 *
879 * @param Authentication $login Authenticaqtion instance
880 *
881 * @return boolean
882 */
883 public function showPublicPages(Authentication $login)
884 {
885 if ($this->prefs['pref_bool_publicpages']) {
886 //if public pages are actives, let's check if we
887 //display them for curent call
888 switch ($this->prefs['pref_publicpages_visibility']) {
889 case self::PUBLIC_PAGES_VISIBILITY_PUBLIC:
890 //pages are publically visibles
891 return true;
892 break;
893 case self::PUBLIC_PAGES_VISIBILITY_RESTRICTED:
894 //pages should be displayed only for up to date members
895 if (
896 $login->isUp2Date()
897 || $login->isAdmin()
898 || $login->isStaff()
899 ) {
900 return true;
901 } else {
902 return false;
903 }
904 break;
905 case self::PUBLIC_PAGES_VISIBILITY_PRIVATE:
906 //pages should be displayed only for staff and admins
907 if ($login->isAdmin() || $login->isStaff()) {
908 return true;
909 } else {
910 return false;
911 }
912 break;
913 default:
914 //should never be there
915 return false;
916 break;
917 }
918 } else {
919 return false;
920 }
921 }
922
923 /**
924 * Global getter method
925 *
926 * @param string $name name of the property we want to retrive
927 *
928 * @return false|object the called property
929 */
930 public function __get($name)
931 {
932 $forbidden = array('defaults');
933 $virtuals = array('vpref_email_newadh');
934
935 if (!in_array($name, $forbidden) && isset($this->prefs[$name])) {
936 if (
937 GALETTE_MODE === 'DEMO'
938 && $name == 'pref_mail_method'
939 ) {
940 return GaletteMail::METHOD_DISABLED;
941 } else {
942 if ($name == 'pref_adhesion_form' && $this->prefs[$name] == '') {
943 $this->prefs[$name] = self::$defaults['pref_adhesion_form'];
944 }
945 $value = $this->prefs[$name];
946 if (TYPE_DB === \Galette\Core\Db::PGSQL) {
947 if ($value === 'f') {
948 $value = false;
949 }
950 }
951
952 if (in_array($name, ['pref_email_newadh'])) {
953 $values = explode(',', $value);
954 $value = $values[0]; //take first as default
955 }
956
957 return $value;
958 }
959 } elseif (in_array($name, $virtuals)) {
960 $virtual = str_replace('vpref_', 'pref_', $name);
961 return explode(',', $this->prefs[$virtual]);
962 } else {
963 Analog::log(
964 'Preference `' . $name . '` is not set or is forbidden',
965 Analog::INFO
966 );
967 return false;
968 }
969 }
970
971 /**
972 * Get default preferences
973 *
974 * @return array
975 */
976 public function getDefaults()
977 {
978 return self::$defaults;
979 }
980
981 /**
982 * Global setter method
983 *
984 * @param string $name name of the property we want to assign a value to
985 * @param object $value a relevant value for the property
986 *
987 * @return void
988 */
989 public function __set($name, $value)
990 {
991 //does this pref exists ?
992 if (!array_key_exists($name, self::$defaults)) {
993 Analog::log(
994 'Trying to set a preference value which does not seem to exist ('
995 . $name . ')',
996 Analog::WARNING
997 );
998 return false;
999 }
1000
1001 if (
1002 $name == 'pref_email'
1003 || $name == 'pref_email_newadh'
1004 || $name == 'pref_email_reply_to'
1005 ) {
1006 if (GALETTE_MODE === 'DEMO') {
1007 Analog::log(
1008 'Trying to set pref_email while in DEMO.',
1009 Analog::WARNING
1010 );
1011 return;
1012 }
1013 }
1014
1015 // now, check validity
1016 if ($value != '') {
1017 $value = $this->validateValue($name, $value);
1018 }
1019
1020 //some values need to be changed (eg. passwords)
1021 if ($name == 'pref_admin_pass') {
1022 $value = password_hash($value, PASSWORD_BCRYPT);
1023 }
1024
1025 //okay, let's update value
1026 $this->prefs[$name] = $value;
1027 }
1028
1029 /**
1030 * Get instance URL from configuration (if set) or guessed if not
1031 *
1032 * @return string
1033 */
1034 public function getURL()
1035 {
1036 $url = null;
1037 if (isset($this->prefs['pref_galette_url']) && !empty($this->prefs['pref_galette_url'])) {
1038 $url = $this->prefs['pref_galette_url'];
1039 } else {
1040 $url = $this->getDefaultURL();
1041 }
1042 return $url;
1043 }
1044
1045 /**
1046 * Get default URL (when not setted by user in preferences)
1047 *
1048 * @return string
1049 */
1050 public function getDefaultURL()
1051 {
1052 $scheme = (isset($_SERVER['HTTPS']) ? 'https' : 'http');
1053 $uri = $scheme . '://' . $_SERVER['HTTP_HOST'];
1054 return $uri;
1055 }
1056
1057 /**
1058 * Check member cards sizes
1059 * Always a A4/portrait
1060 *
1061 * @return array
1062 */
1063 public function checkCardsSizes()
1064 {
1065 $warning_detected = [];
1066 //check page width
1067 $max = 210;
1068 //margins
1069 $size = $this->pref_card_marges_h * 2;
1070 //cards
1071 $size += PdfMembersCards::getWidth() * PdfMembersCards::getCols();
1072 //spacing
1073 $size += $this->pref_card_hspace * (PdfMembersCards::getCols() - 1);
1074 if ($size > $max) {
1075 $warning_detected[] = _T('Current cards configuration may exceed page width!');
1076 }
1077
1078 $max = 297;
1079 //margins
1080 $size = $this->pref_card_marges_v * 2;
1081 //cards
1082 $size += PdfMembersCards::getHeight() * PdfMembersCards::getRows();
1083 //spacing
1084 $size += $this->pref_card_vspace * (PdfMembersCards::getRows() - 1);
1085 if ($size > $max) {
1086 $warning_detected[] = _T('Current cards configuration may exceed page height!');
1087 }
1088
1089 return $warning_detected;
1090 }
1091
1092 /**
1093 * Get errors
1094 *
1095 * @return array
1096 */
1097 public function getErrors()
1098 {
1099 return $this->errors;
1100 }
1101 }