3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
10 * Copyright © 2007-2014 The Galette Team
12 * This file is part of Galette (http://galette.tuxfamily.org).
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.
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.
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/>.
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
36 namespace Galette\Core
;
39 use Galette\Entity\Adherent
;
40 use Galette\Entity\Status
;
42 use Galette\IO\PdfMembersCards
;
43 use Galette\Repository\Members
;
46 * Preferences for galette
51 * @author Johan Cwiklinski <johan@x-tnd.be>
52 * @copyright 2007-2014 The Galette Team
53 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
54 * @link http://galette.tuxfamily.org
55 * @since Available since 0.7dev - 2007-10-14
63 const TABLE
= 'preferences';
64 const PK
= 'nom_pref';
66 /** Postal address will be the one given in the preferences */
67 const POSTAL_ADDRESS_FROM_PREFS
= 0;
68 /** Postal address will be the one of the selected staff member */
69 const POSTAL_ADDRESS_FROM_STAFF
= 1;
71 /** Public pages stuff */
72 /** Public pages are publically visibles */
73 const PUBLIC_PAGES_VISIBILITY_PUBLIC
= 0;
74 /** Public pages are visibles for up to date members only */
75 const PUBLIC_PAGES_VISIBILITY_RESTRICTED
= 1;
76 /** Public pages are visibles for admin and staff members only */
77 const PUBLIC_PAGES_VISIBILITY_PRIVATE
= 2;
79 const LOG_DISABLED
= 0;
80 const LOG_ENABLED
= 1;
82 /** No password strength */
84 /** Weak password strength */
86 /** Medium password strength */
88 /** Strong password strength */
90 /** Very strong password strength */
91 const PWD_VERY_STRONG
= 4;
93 private static $fields = array(
98 private static $defaults = array(
99 'pref_admin_login' => 'admin',
100 'pref_admin_pass' => 'admin',
101 'pref_nom' => 'Galette',
103 'pref_adresse' => '-',
104 'pref_adresse2' => '',
108 'pref_postal_adress' => self
::POSTAL_ADDRESS_FROM_PREFS
,
109 'pref_postal_staff_member' => '',
110 'pref_lang' => I18n
::DEFAULT_LANG
,
111 'pref_numrows' => 30,
112 'pref_log' => self
::LOG_ENABLED
,
113 'pref_statut' => Status
::DEFAULT_STATUS
,
114 /* Preferences for emails */
115 'pref_email_nom' => 'Galette',
116 'pref_email' => 'mail@domain.com',
117 'pref_email_newadh' => 'mail@domain.com',
118 'pref_bool_mailadh' => false,
119 'pref_editor_enabled' => false,
120 'pref_mail_method' => GaletteMail
::METHOD_DISABLED
,
121 'pref_mail_smtp' => '',
122 'pref_mail_smtp_host' => '',
123 'pref_mail_smtp_auth' => false,
124 'pref_mail_smtp_secure' => false,
125 'pref_mail_smtp_port' => '',
126 'pref_mail_smtp_user' => '',
127 'pref_mail_smtp_password' => '',
128 'pref_membership_ext' => 12,
129 'pref_beg_membership' => '',
130 'pref_membership_offermonths' => 0,
131 'pref_email_reply_to' => '',
132 'pref_website' => '',
133 /* Preferences for labels */
134 'pref_etiq_marges_v' => 10,
135 'pref_etiq_marges_h' => 10,
136 'pref_etiq_hspace' => 10,
137 'pref_etiq_vspace' => 5,
138 'pref_etiq_hsize' => 90,
139 'pref_etiq_vsize' => 35,
140 'pref_etiq_cols' => 2,
141 'pref_etiq_rows' => 7,
142 'pref_etiq_corps' => 12,
143 /* Preferences for members cards */
144 'pref_card_abrev' => 'GALETTE',
145 'pref_card_strip' => 'Gestion d\'Adherents en Ligne Extrêmement Tarabiscotée',
146 'pref_card_tcol' => 'FFFFFF',
147 'pref_card_scol' => '8C2453',
148 'pref_card_bcol' => '53248C',
149 'pref_card_hcol' => '248C53',
150 'pref_bool_display_title' => false,
151 'pref_card_address' => 1,
152 'pref_card_year' => '',
153 'pref_card_marges_v' => 15,
154 'pref_card_marges_h' => 20,
155 'pref_card_vspace' => 5,
156 'pref_card_hspace' => 10,
157 'pref_card_self' => 1,
158 'pref_theme' => 'default',
159 'pref_bool_publicpages' => true,
160 'pref_publicpages_visibility' => self
::PUBLIC_PAGES_VISIBILITY_RESTRICTED
,
161 'pref_bool_selfsubscribe' => true,
162 'pref_googleplus' => '',
163 'pref_facebook' => '',
164 'pref_twitter' => '',
166 'pref_linkedin' => '',
167 'pref_mail_sign' => "{NAME}\r\n\r\n{WEBSITE}\r\n{GOOGLEPLUS}\r\n{FACEBOOK}\r\n{TWITTER}\r\n{LINKEDIN}\r\n{VIADEO}",
168 /* New contribution script */
169 'pref_new_contrib_script' => '',
170 'pref_bool_wrap_mails' => true,
171 'pref_rss_url' => 'http://galette.eu/dc/index.php/feed/atom',
172 'pref_show_id' => false,
173 'pref_adhesion_form' => '\Galette\IO\PdfAdhesionForm',
174 'pref_mail_allow_unsecure' => false,
175 'pref_instance_uuid' => '',
176 'pref_registration_uuid' => '',
177 'pref_telemetry_date' => '',
178 'pref_registration_date' => '',
180 'pref_filter_account' => Members
::ALL_ACCOUNTS
,
181 'pref_galette_url' => '',
182 'pref_redirect_on_create' => Adherent
::AFTER_ADD_DEFAULT
,
183 /* Security related */
184 'pref_password_length' => 6,
185 'pref_password_blacklist' => false,
186 'pref_password_strength' => self
::PWD_NONE
189 // flagging required fields
190 private $required = array(
195 'pref_etiq_marges_v',
196 'pref_etiq_marges_h',
206 'pref_card_marges_v',
207 'pref_card_marges_h',
213 * Default constructor
215 * @param Db $zdb Db instance
216 * @param boolean $load Automatically load preferences on load
220 public function __construct(Db
$zdb, $load = true)
225 $this->checkUpdate();
230 * Check if all fields referenced in the default array does exists,
235 private function checkUpdate()
239 foreach (self
::$defaults as $k => $v) {
240 if (!isset($this->prefs
[$k])) {
241 $this->prefs
[$k] = $v;
243 'The field `' . $k . '` does not exists, Galette will attempt to create it.',
253 if ($proceed !== false) {
255 $insert = $this->zdb
->insert(self
::TABLE
);
258 'nom_pref' => ':nom_pref',
259 'val_pref' => ':val_pref'
262 $stmt = $this->zdb
->sql
->prepareStatementForSqlObject($insert);
264 foreach ($params as $p) {
267 'nom_pref' => $p['nom_pref'],
268 'val_pref' => $p['val_pref']
272 } catch (\Exception
$e) {
274 'Unable to add missing preferences.' . $e->getMessage(),
281 'Missing preferences were successfully stored into database.',
288 * Load current preferences from database.
292 public function load()
294 $this->prefs
= array();
297 $result = $this->zdb
->selectAll(self
::TABLE
);
298 foreach ($result as $pref) {
299 $this->prefs
[$pref->nom_pref
] = $pref->val_pref
;
302 } catch (\Exception
$e) {
304 'Preferences cannot be loaded. Galette should not work without ' .
305 'preferences. Exiting.',
313 * Set default preferences at install time
315 * @param string $lang language selected at install screen
316 * @param string $adm_login admin login entered at install time
317 * @param string $adm_pass admin password entered at install time
319 * @return boolean|\Exception
321 public function installInit($lang, $adm_login, $adm_pass)
324 //first, we drop all values
325 $delete = $this->zdb
->delete(self
::TABLE
);
326 $this->zdb
->execute($delete);
328 //we then replace default values with the ones user has selected
329 $values = self
::$defaults;
330 $values['pref_lang'] = $lang;
331 $values['pref_admin_login'] = $adm_login;
332 $values['pref_admin_pass'] = $adm_pass;
333 $values['pref_card_year'] = date('Y');
335 $insert = $this->zdb
->insert(self
::TABLE
);
338 'nom_pref' => ':nom_pref',
339 'val_pref' => ':val_pref'
342 $stmt = $this->zdb
->sql
->prepareStatementForSqlObject($insert);
344 foreach ($values as $k => $v) {
354 'Default preferences were successfully stored into database.',
358 } catch (\Exception
$e) {
360 'Unable to initialize default preferences.' . $e->getMessage(),
368 * Returns all preferences keys
372 public function getFieldsNames()
374 return array_keys($this->prefs
);
380 * @param array $values Values
381 * @param Login $login Logged in user
385 public function check(array $values, Login
$login)
387 $insert_values = array();
388 if ($login->isSuperAdmin() && GALETTE_MODE
!== 'DEMO') {
389 $this->required
[] = 'pref_admin_login';
393 foreach ($this->getFieldsNames() as $fieldname) {
394 if (isset($values[$fieldname])) {
395 $value = trim($values[$fieldname]);
400 // now, check validity
402 switch ($fieldname) {
403 case 'pref_admin_login':
404 if (GALETTE_MODE
=== 'DEMO') {
406 'Trying to set superadmin login while in DEMO.',
410 if (strlen($value) < 4) {
411 $this->errors
[] = _T("- The username must be composed of at least 4 characters!");
413 //check if login is already taken
414 if ($login->loginExists($value)) {
415 $this->errors
[] = _T("- This username is already used by another member !");
421 if (!is_numeric($value) ||
$value < 0) {
422 $this->errors
[] = _T("- The numbers and measures have to be integers!");
425 case 'pref_etiq_marges_h':
426 case 'pref_etiq_marges_v':
427 case 'pref_etiq_hspace':
428 case 'pref_etiq_vspace':
429 case 'pref_etiq_hsize':
430 case 'pref_etiq_vsize':
431 case 'pref_etiq_cols':
432 case 'pref_etiq_rows':
433 case 'pref_etiq_corps':
434 case 'pref_card_marges_v':
435 case 'pref_card_marges_h':
436 case 'pref_card_hspace':
437 case 'pref_card_vspace':
438 // prevent division by zero
439 if ($fieldname == 'pref_numrows' && $value == '0') {
442 if (!is_numeric($value) ||
$value < 0) {
443 $this->errors
[] = _T("- The numbers and measures have to be integers!");
446 case 'pref_card_tcol':
447 // Set strip text color to white
448 if (!preg_match("/#([0-9A-F]{6})/i", $value)) {
452 case 'pref_card_scol':
453 case 'pref_card_bcol':
454 case 'pref_card_hcol':
455 // Set strip background colors to black
456 if (!preg_match("/#([0-9A-F]{6})/i", $value)) {
460 case 'pref_admin_pass':
461 if (GALETTE_MODE
== 'DEMO') {
463 'Trying to set superadmin pass while in DEMO.',
467 $pwcheck = new \Galette\Util\
Password($this);
468 $pwcheck->addPersonalInformation(['pref_admin_login' => $this->pref_admin_login
]);
469 if (!$pwcheck->isValid($value)) {
470 $this->errors
= array_merge(
472 $pwcheck->getErrors()
477 case 'pref_membership_ext':
478 if (!is_numeric($value) ||
$value < 0) {
479 $this->errors
[] = _T("- Invalid number of months of membership extension.");
482 case 'pref_beg_membership':
483 $beg_membership = explode("/", $value);
484 if (count($beg_membership) != 2) {
485 $this->errors
[] = _T("- Invalid format of beginning of membership.");
488 if (!checkdate($beg_membership[1], $beg_membership[0], $now['year'])) {
489 $this->errors
[] = _T("- Invalid date for beginning of membership.");
493 case 'pref_membership_offermonths':
494 if (!is_numeric($value) ||
$value < 0) {
495 $this->errors
[] = _T("- Invalid number of offered months.");
498 case 'pref_card_year':
499 if ($value !== 'DEADLINE' && !preg_match('/^(?:\d{4}|\d{2})(\D?)(?:\d{4}|\d{2})$/', $value)) {
500 $this->errors
[] = _T("- Invalid year for cards.");
506 $insert_values[$fieldname] = $value;
511 GALETTE_MODE
!== 'DEMO'
512 && isset($insert_values['pref_mail_method'])
514 if ($insert_values['pref_mail_method'] > GaletteMail
::METHOD_DISABLED
) {
516 !isset($insert_values['pref_email_nom'])
517 ||
$insert_values['pref_email_nom'] == ''
519 $this->errors
[] = _T("- You must indicate a sender name for emails!");
522 !isset($insert_values['pref_email'])
523 ||
$insert_values['pref_email'] == ''
525 $this->errors
[] = _T("- You must indicate an email address Galette should use to send emails!");
527 if ($insert_values['pref_mail_method'] == GaletteMail
::METHOD_SMTP
) {
529 !isset($insert_values['pref_mail_smtp_host'])
530 ||
$insert_values['pref_mail_smtp_host'] == ''
532 $this->errors
[] = _T("- You must indicate the SMTP server you want to use!");
536 $insert_values['pref_mail_method'] == GaletteMail
::METHOD_GMAIL
537 ||
($insert_values['pref_mail_method'] == GaletteMail
::METHOD_SMTP
538 && $insert_values['pref_mail_smtp_auth'])
541 !isset($insert_values['pref_mail_smtp_user'])
542 ||
trim($insert_values['pref_mail_smtp_user']) == ''
544 $this->errors
[] = _T("- You must provide a login for SMTP authentication.");
547 !isset($insert_values['pref_mail_smtp_password'])
548 ||
($insert_values['pref_mail_smtp_password']) == ''
550 $this->errors
[] = _T("- You must provide a password for SMTP authentication.");
557 isset($insert_values['pref_beg_membership'])
558 && $insert_values['pref_beg_membership'] != ''
559 && isset($insert_values['pref_membership_ext'])
560 && $insert_values['pref_membership_ext'] != ''
562 $this->errors
[] = _T("- Default membership extention and beginning of membership are mutually exclusive.");
566 isset($insert_values['pref_membership_offermonths'])
567 && (int)$insert_values['pref_membership_offermonths'] > 0
568 && isset($insert_values['pref_membership_ext'])
569 && $insert_values['pref_membership_ext'] != ''
571 $this->errors
[] = _T("- Offering months is only compatible with beginning of membership.");
574 // missing required fields?
575 foreach ($this->required
as $val) {
576 if (!isset($values[$val]) ||
isset($values[$val]) && trim($values[$val]) == '') {
577 $this->errors
[] = str_replace(
580 _T("- Mandatory field %field empty.")
585 if (GALETTE_MODE
!== 'DEMO' && isset($values['pref_admin_pass_check'])) {
586 // Check passwords. Hash will be done into the Preferences class
587 if (strcmp($insert_values['pref_admin_pass'], $values['pref_admin_pass_check']) != 0) {
588 $this->errors
[] = _T("Passwords mismatch");
593 if (isset($insert_values['pref_postal_adress'])) {
594 $value = $insert_values['pref_postal_adress'];
595 if ($value == Preferences
::POSTAL_ADDRESS_FROM_PREFS
) {
596 if (isset($insert_values['pref_postal_staff_member'])) {
597 unset($insert_values['pref_postal_staff_member']);
599 } elseif ($value == Preferences
::POSTAL_ADDRESS_FROM_STAFF
) {
600 if (!isset($value) ||
$value < 1) {
601 $this->errors
[] = _T("You have to select a staff member");
606 // update preferences
607 foreach ($insert_values as $champ => $valeur) {
609 $login->isSuperAdmin()
610 ||
(!$login->isSuperAdmin()
611 && ($champ != 'pref_admin_pass' && $champ != 'pref_admin_login'))
614 ($champ == "pref_admin_pass" && $_POST['pref_admin_pass'] != '')
615 ||
($champ != "pref_admin_pass")
617 $this->$champ = $valeur;
622 return 0 === count($this->errors
);
626 * Will store all preferences in the database
630 public function store()
633 $this->zdb
->connection
->beginTransaction();
634 $update = $this->zdb
->update(self
::TABLE
);
637 'val_pref' => ':val_pref'
639 )->where
->equalTo('nom_pref', ':nom_pref');
641 $stmt = $this->zdb
->sql
->prepareStatementForSqlObject($update);
643 foreach (self
::$defaults as $k => $v) {
645 GALETTE_MODE
== 'DEMO'
646 && in_array($k, ['pref_admin_pass', 'pref_admin_login', 'pref_mail_method'])
650 Analog
::log('Storing ' . $k, Analog
::DEBUG
);
652 $value = $this->prefs
[$k];
653 //do not store pdf_adhesion_form, it's designed to be overriden by plugin
654 if ($k === 'pref_adhesion_form') {
655 if (trim($v) == '') {
656 //Reset to default, should not be empty
657 $v = self
::$defaults['pref_adhesion_form'];
664 'val_pref' => $value,
669 $this->zdb
->connection
->commit();
671 'Preferences were successfully stored into database.',
675 } catch (\Exception
$e) {
676 $this->zdb
->connection
->rollBack();
680 $messages[] = $e->getMessage();
681 } while ($e = $e->getPrevious());
684 'Unable to store preferences | ' . print_r($messages, true),
692 * Returns postal address
694 * @return string postal address
696 public function getPostalAddress()
707 $replacements = null;
709 if ($this->prefs
['pref_postal_adress'] == self
::POSTAL_ADDRESS_FROM_PREFS
) {
710 $_address = $this->prefs
['pref_adresse'];
711 if ($this->prefs
['pref_adresse2'] && $this->prefs
['pref_adresse2'] != '') {
712 $_address .= "\n" . $this->prefs
['pref_adresse2'];
714 $replacements = array(
715 $this->prefs
['pref_nom'],
718 $this->prefs
['pref_cp'],
719 $this->prefs
['pref_ville'],
720 $this->prefs
['pref_pays']
723 //get selected staff member address
724 $adh = new Adherent($this->zdb
, (int)$this->prefs
['pref_postal_staff_member']);
725 $_complement = preg_replace(
726 array('/%name/', '/%status/'),
727 array($this->prefs
['pref_nom'], $adh->sstatus
),
728 _T("%name association's %status")
730 $_address = $adh->address
;
731 if ($adh->address_continuation
&& $adh->address_continuation
!= '') {
732 $_address .= "\n" . $adh->address_continuation
;
734 $replacements = array(
735 $adh->sfullname
. "\n",
744 /*FIXME: i18n fails :/ */
748 _T("%name\n%complement\n%address\n%zip %town - %country")
753 "%name%complement%address\n%zip %town - %country"
759 * Are public pages visibles?
761 * @param Authentication $login Authenticaqtion instance
765 public function showPublicPages(Authentication
$login)
767 if ($this->prefs
['pref_bool_publicpages']) {
768 //if public pages are actives, let's check if we
769 //display them for curent call
770 switch ($this->prefs
['pref_publicpages_visibility']) {
771 case self
::PUBLIC_PAGES_VISIBILITY_PUBLIC
:
772 //pages are publically visibles
775 case self
::PUBLIC_PAGES_VISIBILITY_RESTRICTED
:
776 //pages should be displayed only for up to date members
787 case self
::PUBLIC_PAGES_VISIBILITY_PRIVATE
:
788 //pages should be displayed only for staff and admins
789 if ($login->isAdmin() ||
$login->isStaff()) {
796 //should never be there
806 * Global getter method
808 * @param string $name name of the property we want to retrive
810 * @return false|object the called property
812 public function __get($name)
814 $forbidden = array('logged', 'admin', 'active', 'defaults');
815 $virtuals = array('vpref_email_newadh');
817 if (!in_array($name, $forbidden) && isset($this->prefs
[$name])) {
819 GALETTE_MODE
=== 'DEMO'
820 && $name == 'pref_mail_method'
822 return GaletteMail
::METHOD_DISABLED
;
824 if ($name == 'pref_adhesion_form' && $this->prefs
[$name] == '') {
825 $this->prefs
[$name] = self
::$defaults['pref_adhesion_form'];
827 $value = $this->prefs
[$name];
828 if (TYPE_DB
=== \Galette\Core\Db
::PGSQL
) {
829 if ($value === 'f') {
834 if (in_array($name, ['pref_email_newadh'])) {
835 $values = explode(',', $value);
836 $value = $values[0]; //take first as default
841 } elseif (in_array($name, $virtuals)) {
842 $virtual = str_replace('vpref_', 'pref_', $name);
843 return explode(',', $this->prefs
[$virtual]);
846 'Preference `' . $name . '` is not set or is forbidden',
854 * Get default preferences
858 public function getDefaults()
860 return self
::$defaults;
864 * Global setter method
866 * @param string $name name of the property we want to assign a value to
867 * @param object $value a relevant value for the property
871 public function __set($name, $value)
873 //does this pref exists ?
874 if (!array_key_exists($name, self
::$defaults)) {
876 'Trying to set a preference value which does not seem to exist ('
884 $name == 'pref_email'
885 ||
$name == 'pref_email_newadh'
886 ||
$name == 'pref_email_reply_to'
888 if (GALETTE_MODE
=== 'DEMO') {
890 'Trying to set pref_email while in DEMO.',
896 //check emails validity
897 //may be a comma separated list of valid emails identifiers:
898 //"The Name <mail@domain.com>,The Other <other@mail.com>" expect for reply_to.
900 if (trim($value) != '') {
901 if ($name == 'pref_email_newadh') {
902 $addresses = explode(',', $value);
904 $addresses = [$value];
907 foreach ($addresses as $address) {
908 if (!GaletteMail
::isValidEmail($address)) {
909 $msg = str_replace('%s', $address, _T("Invalid E-Mail address: %s"));
910 Analog
::log($msg, Analog
::WARNING
);
911 $this->errors
[] = $msg;
916 //some values need to be changed (eg. passwords)
917 if ($name == 'pref_admin_pass') {
918 $value = password_hash($value, PASSWORD_BCRYPT
);
921 //okay, let's update value
922 $this->prefs
[$name] = $value;
926 * Get instance URL from configuration (if set) or guessed if not
930 public function getURL()
933 if (isset($this->prefs
['pref_galette_url']) && !empty($this->prefs
['pref_galette_url'])) {
934 $url = $this->prefs
['pref_galette_url'];
936 $url = $this->getDefaultURL();
942 * Get default URL (when not setted by user in preferences)
946 public function getDefaultURL()
948 $scheme = (isset($_SERVER['HTTPS']) ?
'https' : 'http');
949 $uri = $scheme . '://' . $_SERVER['HTTP_HOST'];
954 * Check member cards sizes
955 * Always a A4/portrait
959 public function checkCardsSizes()
961 $warning_detected = [];
965 $size = $this->pref_card_marges_h
* 2;
967 $size +
= PdfMembersCards
::getWidth() * PdfMembersCards
::getCols();
969 $size +
= $this->pref_card_hspace
* (PdfMembersCards
::getCols() - 1);
971 $warning_detected[] = _T('Current cards configuration may exceed page width!');
976 $size = $this->pref_card_marges_v
* 2;
978 $size +
= PdfMembersCards
::getHeight() * PdfMembersCards
::getRows();
980 $size +
= $this->pref_card_vspace
* (PdfMembersCards
::getRows() - 1);
982 $warning_detected[] = _T('Current cards configuration may exceed page height!');
985 return $warning_detected;
993 public function getErrors()
995 return $this->errors
;