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