dolibarr 25.0.0-alpha
user.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 2002-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (c) 2002-2003 Jean-Louis Bergamo <jlb@j1b.org>
4 * Copyright (c) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6 * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
7 * Copyright (C) 2005-2024 Regis Houssin <regis.houssin@inodbox.com>
8 * Copyright (C) 2005 Lionel Cousteix <etm_ltd@tiscali.co.uk>
9 * Copyright (C) 2011 Herve Prot <herve.prot@symeos.com>
10 * Copyright (C) 2013-2019 Philippe Grand <philippe.grand@atoo-net.com>
11 * Copyright (C) 2013-2015 Alexandre Spangaro <aspangaro@open-dsi.fr>
12 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
13 * Copyright (C) 2018 charlene Benke <charlie@patas-monkey.com>
14 * Copyright (C) 2018-2021 Nicolas ZABOURI <info@inovea-conseil.com>
15 * Copyright (C) 2019-2026 Frédéric France <frederic.france@free.fr>
16 * Copyright (C) 2019 Abbes Bahfir <dolipar@dolipar.org>
17 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
18 * Copyright (C) 2024 Lenin Rivas <lenin.rivas777@gmail.com>
19 * Copyright (C) 2026 Anthony Berton <anthony.berton@bb2a.fr>
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 3 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <https://www.gnu.org/licenses/>.
33 */
34
41require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
42require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
43require_once DOL_DOCUMENT_ROOT.'/user/class/usergroup.class.php';
44require_once DOL_DOCUMENT_ROOT.'/core/class/commonpeople.class.php';
45
46
50class User extends CommonObject
51{
52 use CommonPeople;
53
57 public $element = 'user';
58
62 public $table_element = 'user';
63
67 public $fk_element = 'fk_user';
68
72 public $picto = 'user';
73
77 public $id = 0;
78
84 public $statut;
85
89 public $status;
90
94 public $openid;
95
99 public $ldap_sid;
103 public $search_sid;
107 public $employee;
111 public $civility_code;
112
116 public $fullname;
117
121 public $gender;
122
126 public $birth;
127
131 public $email;
132
136 public $email_oauth2;
137
141 public $personal_email;
142
146 public $socialnetworks;
147
151 public $job;
152
156 public $signature;
157
161 public $office_phone;
162
166 public $office_fax;
167
171 public $user_mobile;
172
176 public $personal_mobile;
177
181 public $admin;
182
186 public $login;
187
191 public $api_key;
192
196 public $pass;
197
201 public $pass_crypted;
202
206 public $pass_indatabase;
207
211 public $pass_indatabase_crypted;
212
216 public $pass_temp;
217
221 public $force_pass_change = 0;
222
228 public $datec;
229
235 public $datem;
236
240 public $socid;
241
245 public $contact_id;
246
250 public $fk_member;
251
255 public $fk_user;
256
260 public $fk_user_expense_validator;
261
265 public $fk_user_holiday_validator;
266
270 public $clicktodial_url;
271
275 public $clicktodial_login;
276
280 public $clicktodial_password;
281
285 public $clicktodial_poste;
286
290 public $clicktodial_loaded;
291
292
296 public $datelastpassvalidation;
300 public $datelastlogin;
304 public $datepreviouslogin;
308 public $flagdelsessionsbefore;
312 public $iplastlogin;
316 public $ippreviouslogin;
320 public $datestartvalidity;
324 public $dateendvalidity;
325
329 public $photo;
330
334 public $lang;
335
339 public $rights;
340
344 public $all_permissions_are_loaded;
345
349 public $nb_rights;
350
354 public $user_group_list;
355
359 private $_tab_loaded = array();
360
364 public $conf;
365
369 public $default_values; // To store default values for user. Loaded by loadDefaultValues().
370
374 public $lastsearch_values_tmp; // To store current search criteria for user
378 public $lastsearch_values; // To store last saved search criteria for user
379
383 public $users = array();
387 public $parentof; // To store an array of all parents for all ids.
391 private $cache_childids; // Cache array of already loaded children
392
397 public $accountancy_code_user_general; // Accountancy code in prevision of the complete accountancy module
398
402 public $accountancy_code; // Accountancy code in prevision of the complete accountancy module
403
407 public $thm; // Average cost of employee - Used for valuation of time spent
411 public $tjm; // Average cost of employee
412
416 public $salary; // Monthly salary - Denormalized value from llx_user_employment
420 public $salaryextra; // Monthly salary extra - Denormalized value from llx_user_employment
424 public $weeklyhours; // Weekly hours - Denormalized value from llx_user_employment
425
429 public $color;
430
434 public $dateemployment; // Define date of employment by company
438 public $dateemploymentend; // Define date of employment end by company
439
443 public $default_c_exp_tax_cat;
444
448 public $ref_employee;
449
453 public $national_registration_number;
454
458 public $default_range;
459
464 public $fk_warehouse;
465
469 public $fk_establishment;
470
474 public $label_establishment;
475
480 public $usergroup_entity;
481
482 public $fields = array(
483 'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'index' => 1, 'position' => 1, 'comment' => 'Id'),
484 'lastname' => array('type' => 'varchar(50)', 'label' => 'Lastname', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'showoncombobox' => 1, 'index' => 1, 'position' => 20, 'searchall' => 1),
485 'firstname' => array('type' => 'varchar(50)', 'label' => 'Firstname', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'showoncombobox' => 1, 'index' => 1, 'position' => 10, 'searchall' => 1),
486 'fk_warehouse' => array('type' => 'integer:Entrepot:product/stock/class/entrepot.class.php', 'label' => 'Warehouse', 'enabled' => "isModEnabled('stock')", 'visible' => 1, 'notnull' => 0, 'showoncombobox' => 1, 'index' => 1, 'position' => 50, 'searchall' => 1),
487 'ref_employee' => array('type' => 'varchar(50)', 'label' => 'RefEmployee', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'showoncombobox' => 1, 'index' => 1, 'position' => 30, 'searchall' => 1),
488 'national_registration_number' => array('type' => 'varchar(50)', 'label' => 'NationalRegistrationNumber', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'showoncombobox' => 1, 'index' => 1, 'position' => 40, 'searchall' => 1)
489 );
490
491 const STATUS_DISABLED = 0;
492 const STATUS_ENABLED = 1;
493
499 public function __construct($db)
500 {
501 $this->db = $db;
502
503 $this->ismultientitymanaged = 1;
504 $this->isextrafieldmanaged = 1;
505 // User preference
506 $this->clicktodial_loaded = 0;
507
508 // For cache usage
509 $this->all_permissions_are_loaded = 0;
510 $this->nb_rights = 0;
511
512 // Force some default values
513 $this->admin = 0;
514 $this->employee = 1;
515
516 $this->conf = new stdClass();
517 $this->rights = new stdClass();
518 $this->rights->user = new stdClass();
519 $this->rights->user->user = new stdClass();
520 $this->rights->user->self = new stdClass();
521 $this->rights->user->user_advance = new stdClass();
522 $this->rights->user->self_advance = new stdClass();
523 $this->rights->user->group_advance = new stdClass();
524 }
525
540 public function fetch($id = 0, $login = '', $sid = '', $loadpersonalconf = 0, $entity = -1, $email = '', $fk_socpeople = 0, $use_email_oauth2 = 0)
541 {
542 global $conf, $user;
543
544 // Clean parameters
545 $login = trim($login);
546
547 // Get user
548 $sql = "SELECT u.rowid, u.lastname, u.firstname, u.employee, u.gender, u.civility as civility_code, u.birth, u.job,";
549 $sql .= " u.email, u.email_oauth2, u.personal_email,";
550 $sql .= " u.socialnetworks,";
551 $sql .= " u.signature, u.office_phone, u.office_fax, u.user_mobile, u.personal_mobile,";
552 $sql .= " u.address, u.zip, u.town, u.fk_state as state_id, u.fk_country as country_id,";
553 $sql .= " u.admin, u.login, u.note_private, u.note_public,";
554 $sql .= " u.pass, u.pass_crypted, u.pass_temp, u.force_pass_change, u.api_key,";
555 $sql .= " u.fk_soc, u.fk_socpeople, u.fk_member, u.fk_user, u.ldap_sid, u.fk_user_expense_validator, u.fk_user_holiday_validator,";
556 $sql .= " fk_user_creat as user_creation_id, fk_user_modif as user_modification_id,";
557 $sql .= " u.statut as status, u.lang, u.entity,";
558 $sql .= " u.datec as datec,";
559 $sql .= " GREATEST(u.tms, uef.tms) as datem,";
560 $sql .= " u.datelastlogin as datel,";
561 $sql .= " u.datepreviouslogin as datep,";
562 $sql .= " u.flagdelsessionsbefore,";
563 $sql .= " u.iplastlogin,";
564 $sql .= " u.ippreviouslogin,";
565 $sql .= " u.datelastpassvalidation,";
566 $sql .= " u.datestartvalidity,";
567 $sql .= " u.dateendvalidity,";
568 $sql .= " u.photo as photo,";
569 $sql .= " u.openid as openid,";
570 $sql .= " u.accountancy_code_user_general,";
571 $sql .= " u.accountancy_code,";
572 $sql .= " u.thm,";
573 $sql .= " u.tjm,";
574 $sql .= " u.salary,";
575 $sql .= " u.salaryextra,";
576 $sql .= " u.weeklyhours,";
577 $sql .= " u.color,";
578 $sql .= " u.dateemployment, u.dateemploymentend,";
579 $sql .= " u.fk_warehouse,";
580 $sql .= " u.ref_ext,";
581 $sql .= " u.default_range, u.default_c_exp_tax_cat,"; // Expense report default mode
582 $sql .= " u.national_registration_number,";
583 $sql .= " u.ref_employee,";
584 $sql .= " c.code as country_code, c.label as country,";
585 $sql .= " d.code_departement as state_code, d.nom as state,";
586 $sql .= " s.label as label_establishment, u.fk_establishment";
587 $sql .= " FROM ".$this->db->prefix()."user as u";
588 $sql .= " LEFT JOIN ".$this->db->prefix()."user_extrafields as uef ON uef.fk_object = u.rowid";
589 $sql .= " LEFT JOIN ".$this->db->prefix()."c_country as c ON u.fk_country = c.rowid";
590 $sql .= " LEFT JOIN ".$this->db->prefix()."c_departements as d ON u.fk_state = d.rowid";
591 $sql .= " LEFT JOIN ".$this->db->prefix()."establishment as s ON u.fk_establishment = s.rowid";
592
593 if ($id > 0) {
594 $sql .= " WHERE u.rowid = ".((int) $id);
595 } else {
596 if ($entity < 0) {
597 if ((! isModEnabled('multicompany') || ! getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) && (! empty($user->entity))) {
598 $sql .= " WHERE u.entity IN (0, " . ((int) $conf->entity) . ")";
599 } else {
600 $sql .= " WHERE u.entity IS NOT NULL"; // multicompany is on in transverse mode or user making fetch is on entity 0, so user is allowed to fetch anywhere into database
601 }
602 } else {
603 // The fetch was forced on an entity
604 if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
605 $sql .= " WHERE u.entity IS NOT NULL"; // multicompany is on in transverse mode or user making fetch is on entity 0, so user is allowed to fetch anywhere into database
606 } else {
607 if ($entity != '' && $entity == 0) { // If $entity = 0
608 $sql .= " WHERE u.entity = 0";
609 } else { // if $entity is -1 or > 0
610 $sql .= " WHERE u.entity IN (0, " . ((int) ($entity > 0 ? ((int) $entity) : ((int) $conf->entity))) . ")";
611 }
612 }
613 }
614 }
615
616 if ($sid) {
617 // allows searching for the user by their ActiveDirectory or Samba SID
618 $sql .= " AND (u.ldap_sid = '".$this->db->escape($sid)."' OR u.login = '".$this->db->escape($login)."')";
619 } elseif ($login) {
620 $sql .= " AND u.login = '".$this->db->escape($login)."'";
621 } elseif ($email) {
622 $sql .= " AND (u.email = '".$this->db->escape($email)."'";
623 if ($use_email_oauth2) {
624 $sql .= " OR u.email_oauth2 = '".$this->db->escape($email)."'";
625 }
626 $sql .= ")";
627 } elseif ($fk_socpeople > 0) {
628 $sql .= " AND u.fk_socpeople = ".((int) $fk_socpeople);
629 }
630
631 $sql .= " ORDER BY u.entity ASC"; // Avoid random result when there is 2 login in 2 different entities
632
633 if ($sid) {
634 // allows searching for the user by their ActiveDirectory or Samba SID
635 $sql .= ' '.$this->db->plimit(1);
636 }
637
638 $resql = $this->db->query($sql);
639 if ($resql) {
640 $num = $this->db->num_rows($resql);
641 if ($num > 1) {
642 $this->error = "USERDUPLICATEFOUND";
643 dol_syslog(get_class($this)."::fetch more than 1 user found", LOG_WARNING);
644
645 $this->db->free($resql);
646 return 0;
647 }
648
649 $obj = $this->db->fetch_object($resql);
650 if ($obj) {
651 $this->id = $obj->rowid;
652 $this->ref = $obj->rowid;
653
654 $this->ref_ext = $obj->ref_ext;
655
656 $this->ldap_sid = $obj->ldap_sid;
657 $this->civility_code = $obj->civility_code;
658 $this->lastname = $obj->lastname;
659 $this->firstname = $obj->firstname;
660 $this->ref_employee = $obj->ref_employee;
661 $this->national_registration_number = $obj->national_registration_number;
662
663 $this->employee = $obj->employee;
664
665 $this->login = $obj->login;
666 $this->gender = $obj->gender;
667 $this->birth = $this->db->jdate($obj->birth);
668 $this->pass_indatabase = $obj->pass;
669 $this->pass_indatabase_crypted = $obj->pass_crypted;
670 $this->pass = $obj->pass;
671 $this->pass_temp = $obj->pass_temp;
672
673 $this->force_pass_change = $obj->force_pass_change;
674 $this->datelastpassvalidation = $this->db->jdate($obj->datelastpassvalidation);
675
676 $this->api_key = dolDecrypt($obj->api_key);
677
678 $this->address = $obj->address;
679 $this->zip = $obj->zip;
680 $this->town = $obj->town;
681
682 $this->country_id = $obj->country_id;
683 $this->country_code = $obj->country_id ? $obj->country_code : '';
684 //$this->country = $obj->country_id?($langs->trans('Country'.$obj->country_code)!='Country'.$obj->country_code?$langs->transnoentities('Country'.$obj->country_code):$obj->country):'';
685
686 $this->state_id = $obj->state_id;
687 $this->state_code = $obj->state_code;
688 $this->state = ($obj->state != '-' ? $obj->state : '');
689
690 $this->office_phone = $obj->office_phone;
691 $this->office_fax = $obj->office_fax;
692 $this->user_mobile = $obj->user_mobile;
693 $this->personal_mobile = $obj->personal_mobile;
694 $this->email = $obj->email;
695 $this->email_oauth2 = $obj->email_oauth2;
696 $this->personal_email = $obj->personal_email;
697 $this->socialnetworks = ($obj->socialnetworks ? (array) json_decode($obj->socialnetworks, true) : array());
698 $this->user_creation_id = $obj->user_creation_id;
699 $this->user_modification_id = $obj->user_modification_id;
700
701 $this->job = $obj->job;
702 $this->signature = $obj->signature;
703 $this->admin = $obj->admin;
704 $this->note_public = $obj->note_public;
705 $this->note_private = $obj->note_private;
706
707 $this->statut = $obj->status; // deprecated
708 $this->status = $obj->status;
709
710 $this->photo = $obj->photo;
711 $this->openid = $obj->openid;
712 $this->lang = $obj->lang;
713 $this->entity = $obj->entity;
714
715 $this->accountancy_code_user_general = $obj->accountancy_code_user_general;
716 $this->accountancy_code = $obj->accountancy_code;
717
718 $this->thm = $obj->thm;
719 $this->tjm = $obj->tjm;
720 $this->salary = $obj->salary;
721 $this->salaryextra = $obj->salaryextra;
722 $this->weeklyhours = $obj->weeklyhours;
723 $this->color = $obj->color;
724 $this->dateemployment = $this->db->jdate($obj->dateemployment);
725 $this->dateemploymentend = $this->db->jdate($obj->dateemploymentend);
726
727 $this->datec = $this->db->jdate($obj->datec);
728 $this->datem = $this->db->jdate($obj->datem);
729 $this->datelastlogin = $this->db->jdate($obj->datel);
730 $this->datepreviouslogin = $this->db->jdate($obj->datep);
731 $this->flagdelsessionsbefore = $this->db->jdate($obj->flagdelsessionsbefore, 'gmt');
732 $this->iplastlogin = $obj->iplastlogin;
733 $this->ippreviouslogin = $obj->ippreviouslogin;
734 $this->datestartvalidity = $this->db->jdate($obj->datestartvalidity);
735 $this->dateendvalidity = $this->db->jdate($obj->dateendvalidity);
736
737 $this->socid = $obj->fk_soc;
738 $this->contact_id = $obj->fk_socpeople;
739 $this->fk_member = $obj->fk_member;
740 $this->fk_user = $obj->fk_user;
741 $this->fk_user_expense_validator = $obj->fk_user_expense_validator;
742 $this->fk_user_holiday_validator = $obj->fk_user_holiday_validator;
743
744 $this->default_range = $obj->default_range;
745 $this->default_c_exp_tax_cat = $obj->default_c_exp_tax_cat;
746 $this->fk_warehouse = $obj->fk_warehouse;
747 $this->warehouse_id = $obj->fk_warehouse; // To avoid that some code use $user->warehouse when it is not loaded. It must be loaded with $user->fetch_warehouse() before.
748 $this->warehouse = null; // To avoid that some code use $user->warehouse when it is not loaded. It must be loaded with $user->fetch_warehouse() before.
749 $this->fk_establishment = $obj->fk_establishment;
750 $this->label_establishment = $obj->label_establishment;
751
752 // Protection when module multicompany was set, admin was set to first entity and then, the module was disabled,
753 // in such case, this admin user must be admin for ALL entities.
754 if (!isModEnabled('multicompany') && $this->admin && $this->entity == 1) {
755 $this->entity = 0;
756 }
757
758 // If user is linked to a warehouse, we load it into memory
759 if (isModEnabled('stock') && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && (!empty($this->fk_warehouse) || !empty($this->warehouse_id))) {
760 $this->fetchWarehouse();
761 }
762 // Retrieve all extrafield
763 // fetch optionals attributes and labels
764 $this->fetch_optionals();
765
766 $this->db->free($resql);
767 } else {
768 $this->error = "USERNOTFOUND";
769 dol_syslog(get_class($this)."::fetch user not found", LOG_DEBUG);
770
771 $this->db->free($resql);
772 return 0;
773 }
774 } else {
775 $this->error = $this->db->lasterror();
776 return -1;
777 }
778
779 // To get back the global configuration unique to the user
780 if ($loadpersonalconf) {
781 $result = $this->loadPersonalConf($entity);
782
783 $result = $this->loadDefaultValues();
784
785 if ($result < 0) {
786 $this->error = $this->db->lasterror();
787 return -3;
788 }
789 }
790
791 // Add option to allow an admin internal user to make quick debug for internal users. Not yet implemented completely.
792 // This is a special cas that is allowed to have a GETPOST inside a class.
793 if (GETPOSTINT('forceexternaluser') && $this->admin && empty($this->socid)) {
794 $this->socid = GETPOSTINT('forceexternaluser');
795 }
796
797 return 1;
798 }
799
800
807 public function loadPersonalConf($entity = -1)
808 {
809 global $conf;
810
811 // Load user->conf for user
812 $sql = "SELECT param, value FROM ".$this->db->prefix()."user_param";
813 $sql .= " WHERE fk_user = ".((int) $this->id);
814 if ($entity < 0) {
815 $sql .= " AND entity IN (0, ".((int) $conf->entity).")"; // IN (0, x)
816 } else {
817 $sql .= " AND entity = ".((int) $entity); // 0 or x
818 }
819
820 //dol_syslog(get_class($this).'::fetch load personalized conf', LOG_DEBUG);
821 $resql = $this->db->query($sql);
822 if ($resql) {
823 $num = $this->db->num_rows($resql);
824 $i = 0;
825 while ($i < $num) {
826 $obj = $this->db->fetch_object($resql);
827 $p = (!empty($obj->param) ? $obj->param : '');
828 if (!empty($p)) {
829 $this->conf->$p = $obj->value;
830 }
831 $i++;
832 }
833 $this->db->free($resql);
834
835 return $num;
836 } else {
837 $this->error = $this->db->lasterror();
838
839 return -2;
840 }
841 }
842
848 public function loadDefaultValues()
849 {
850 global $conf;
851
852 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
853 // Load user->default_values for user. TODO Save this in memcached ?
854 require_once DOL_DOCUMENT_ROOT.'/core/class/defaultvalues.class.php';
855
856 $defaultValues = new DefaultValues($this->db);
857 $result = $defaultValues->fetchAll('', '', 0, 0, '(t.user_id:in:0,'.$this->id.') AND (entity:in:'.(isset($this->entity) ? $this->entity : $conf->entity).','.$conf->entity.')'); // User 0 (all) + me (if defined)
858 //$result = $defaultValues->fetchAll('', '', 0, 0, array('t.user_id'=>array(0, $this->id), 'entity'=>array((isset($this->entity) ? $this->entity : $conf->entity), $conf->entity))); // User 0 (all) + me (if defined)
859
860 if (!is_array($result) && $result < 0) {
861 $this->error = $defaultValues->error;
862 $this->errors = $defaultValues->errors;
863 dol_print_error($this->db);
864 return -1;
865 } elseif (count($result) > 0) {
866 foreach ($result as $defval) {
867 if (!empty($defval->page) && !empty($defval->type) && !empty($defval->param)) {
868 $pagewithoutquerystring = $defval->page;
869 $pagequeries = '';
870 $reg = array();
871 if (preg_match('/^([^\?]+)\?(.*)$/', $pagewithoutquerystring, $reg)) { // There is query param
872 $pagewithoutquerystring = $reg[1];
873 $pagequeries = $reg[2];
874 }
875 $this->default_values[$pagewithoutquerystring][$defval->type][$pagequeries ? $pagequeries : '_noquery_'][$defval->param] = $defval->value;
876 }
877 }
878 }
879 if (!empty($this->default_values)) {
880 foreach ($this->default_values as $a => $b) {
881 foreach ($b as $c => $d) {
882 krsort($this->default_values[$a][$c]);
883 }
884 }
885 }
886 }
887 return 1;
888 }
889
896 public function isAdmin()
897 {
898 return $this->admin;
899 }
900
907 public function isExternalUser()
908 {
909 return $this->socid;
910 }
911
923 public function hasRight($module, $permlevel1, $permlevel2 = '')
924 {
925 // For compatibility with bad naming permissions on module
926 $moduletomoduletouse = array(
927 'category' => 'categorie',
928 'compta' => 'comptabilite',
929 'contract' => 'contrat',
930 'member' => 'adherent',
931 'mo' => 'mrp',
932 'order' => 'commande',
933 'produit' => 'product',
934 'productlot' => 'product',
935 'project' => 'projet',
936 'propale' => 'propal',
937 'shipping' => 'expedition',
938 'task' => 'task@projet',
939 'fichinter' => 'ficheinter',
940 'intervention' => 'ficheinter',
941 'inventory' => 'stock',
942 'invoice' => 'facture',
943 'invoice_supplier' => 'facture@fournisseur',
944 'order_supplier' => 'fournisseur',
945 'knowledgerecord' => 'knowledgerecord@knowledgemanagement',
946 'skill@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all"
947 'job@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all"
948 'position@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all"
949 'facturerec' => 'facture',
950 'margins' => 'margin',
951 );
952
953 if (!empty($moduletomoduletouse[$module])) {
954 $module = $moduletomoduletouse[$module];
955 }
956
957 // Compatibility layer for the supplier module split transition (MAIN_USE_NEW_SUPPLIERMOD).
958 // Allows both old and new permission syntaxes to work in parallel during migration.
959 // - Old: $user->hasRight('fournisseur', 'commande', 'lire')
960 // - New: $user->hasRight('supplier_order', 'lire')
961 // External modules are also transparently supported without any change on their side.
962 if (getDolGlobalInt('MAIN_USE_NEW_SUPPLIERMOD')) {
963 // New module names introduced by the split, mapped to their legacy equivalent.
964 // Format: 'new_module' => ['legacy_module', 'legacy_permlevel1']
965 $supplierNewToLegacy = array(
966 'supplier_order' => array('fournisseur', 'commande'),
967 'supplier_invoice' => array('fournisseur', 'facture'),
968 );
969
970 if (isset($supplierNewToLegacy[$module])) {
971 // Caller used new syntax: rewrite to legacy so the rights object resolves correctly.
972 // e.g. hasRight('supplier_order', 'lire') -> hasRight('fournisseur', 'commande', 'lire')
973 $permlevel2 = $permlevel1;
974 $permlevel1 = $supplierNewToLegacy[$module][1]; // e.g. 'commande'
975 $module = $supplierNewToLegacy[$module][0]; // e.g. 'fournisseur'
976 }
977 } else {
978 // Legacy mode: translate new module names back to old ones in case some
979 // updated code calls the new syntax while the option is not yet enabled.
980 $supplierLegacyCompat = array(
981 'supplier_order' => 'fournisseur',
982 'supplier_invoice' => 'fournisseur',
983 );
984
985 if (isset($supplierLegacyCompat[$module])) {
986 // e.g. hasRight('supplier_order', 'lire') stays routed through 'fournisseur'
987 $module = $supplierLegacyCompat[$module];
988 }
989 }
990
991 $moduleRightsMapping = array(
992 'product' => 'produit',
993 'margin' => 'margins',
994 'comptabilite' => 'compta'
995 );
996
997 $rightsPath = $module;
998 if (!empty($moduleRightsMapping[$rightsPath])) {
999 $rightsPath = $moduleRightsMapping[$rightsPath];
1000 }
1001
1002 // If module is abc@module, we check permission user->hasRight(module, abc, permlevel1)
1003 $tmp = explode('@', $rightsPath, 2);
1004 if (!empty($tmp[1])) {
1005 if (strpos($module, '@') !== false) {
1006 $module = $tmp[1];
1007 }
1008 if ($tmp[0] != $tmp[1]) {
1009 // If $module = 'myobject@mymodule'
1010 $rightsPath = $tmp[1];
1011 $permlevel2 = $permlevel1;
1012 $permlevel1 = $tmp[0];
1013 } else {
1014 // If $module = 'abc@abc'
1015 $rightsPath = $tmp[1];
1016 }
1017 }
1018
1019 // In $conf->modules, we have 'accounting', 'product', 'facture', ...
1020 // In $user->rights, we have 'accounting', 'produit', 'facture', ...
1021
1022 if (!isModEnabled($module)) {
1023 return 0;
1024 }
1025
1026 // Special case for external user
1027 if (!empty($this->socid)) {
1028 if ($module == 'societe' && ($permlevel1 == 'creer' || $permlevel1 == 'write')) {
1029 return 0; // An external user never has the permission ->societe->write to see all thirdparties (always restricted to himself)
1030 }
1031 if ($module == 'societe' && $permlevel1 == 'client' && $permlevel2 == 'voir') {
1032 return 0; // An external user never has the permission ->societe->client->voir to see all thirdparties (always restricted to himself)
1033 }
1034 if ($module == 'societe' && $permlevel1 == 'export') {
1035 return 0; // An external user never has the permission ->societe->export to see all thirdparties (always restricted to himself)
1036 }
1037 if ($module == 'societe' && ($permlevel1 == 'supprimer' || $permlevel1 == 'delete')) {
1038 return 0; // An external user never has the permission ->societe->delete to see all thirdparties (always restricted to himself)
1039 }
1040 }
1041
1042 // For compatibility with bad naming permissions on permlevel1
1043 if ($permlevel1 == 'propale') {
1044 $permlevel1 = 'propal';
1045 }
1046 if ($permlevel1 == 'member') {
1047 $permlevel1 = 'adherent';
1048 }
1049 if ($permlevel1 == 'recruitmentcandidature') {
1050 $permlevel1 = 'recruitmentjobposition';
1051 }
1052
1053 if (empty($rightsPath) || empty($this->rights) || empty($this->rights->$rightsPath) || empty($permlevel1)) {
1054 return 0;
1055 }
1056
1057 if ($permlevel2) {
1058 if (!empty($this->rights->$rightsPath->$permlevel1)) {
1059 if (!empty($this->rights->$rightsPath->$permlevel1->$permlevel2)) {
1060 return $this->rights->$rightsPath->$permlevel1->$permlevel2;
1061 }
1062 // For backward compatibility with old permissions called "lire", "creer", "create", "supprimer"
1063 // instead of "read", "write", "delete"
1064 if ($permlevel2 == 'read' && !empty($this->rights->$rightsPath->$permlevel1->lire)) {
1065 return $this->rights->$rightsPath->$permlevel1->lire;
1066 }
1067 if ($permlevel2 == 'write' && !empty($this->rights->$rightsPath->$permlevel1->creer)) {
1068 return $this->rights->$rightsPath->$permlevel1->creer;
1069 }
1070 if ($permlevel2 == 'write' && !empty($this->rights->$rightsPath->$permlevel1->create)) {
1071 return $this->rights->$rightsPath->$permlevel1->create;
1072 }
1073 if ($permlevel2 == 'delete' && !empty($this->rights->$rightsPath->$permlevel1->supprimer)) {
1074 return $this->rights->$rightsPath->$permlevel1->supprimer;
1075 }
1076 }
1077 } else {
1078 if (!empty($this->rights->$rightsPath->$permlevel1)) {
1079 return $this->rights->$rightsPath->$permlevel1;
1080 }
1081 // For backward compatibility with old permissions called "lire", "creer", "create", "supprimer"
1082 // instead of "read", "write", "delete"
1083 if ($permlevel1 == 'read' && !empty($this->rights->$rightsPath->lire)) {
1084 return $this->rights->$rightsPath->lire;
1085 }
1086 if ($permlevel1 == 'write' && !empty($this->rights->$rightsPath->creer)) {
1087 return $this->rights->$rightsPath->creer;
1088 }
1089 if ($permlevel1 == 'write' && !empty($this->rights->$rightsPath->create)) {
1090 return $this->rights->$rightsPath->create;
1091 }
1092 if ($permlevel1 == 'delete' && !empty($this->rights->$rightsPath->supprimer)) {
1093 return $this->rights->$rightsPath->supprimer;
1094 }
1095 }
1096
1097 return 0;
1098 }
1099
1111 public function addrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
1112 {
1113 global $conf, $user, $langs;
1114
1115 $entity = (empty($entity) ? $conf->entity : $entity);
1116
1117 dol_syslog(get_class($this)."::addrights $rid, $allmodule, $allperms, $entity, $notrigger for user id=".$this->id);
1118
1119 if (empty($this->id)) {
1120 $this->error = 'Try to call addrights on an object user with an empty id';
1121 return -1;
1122 }
1123
1124 $error = 0;
1125 $whereforadd = '';
1126
1127 $this->db->begin();
1128
1129 if (!empty($rid)) {
1130 $module = $perms = $subperms = '';
1131
1132 // If we ask to add a given permission, we first load properties of this permission (module, perms and subperms).
1133 $sql = "SELECT module, perms, subperms";
1134 $sql .= " FROM ".$this->db->prefix()."rights_def";
1135 $sql .= " WHERE id = ".((int) $rid);
1136 $sql .= " AND entity = ".((int) $entity);
1137
1138 $result = $this->db->query($sql);
1139 if ($result) {
1140 $obj = $this->db->fetch_object($result);
1141
1142 if ($obj) {
1143 $module = $obj->module;
1144 $perms = $obj->perms;
1145 $subperms = $obj->subperms;
1146 }
1147 } else {
1148 $error++;
1149 dol_print_error($this->db);
1150 }
1151
1152 // Define the where for the permission to add
1153 $whereforadd = "id=".((int) $rid);
1154 // Add also inherited permissions
1155 if (!empty($subperms)) {
1156 $whereforadd .= " OR (module='".$this->db->escape($module)."' AND perms='".$this->db->escape($perms)."' AND (subperms='lire' OR subperms='read'))";
1157 } elseif (!empty($perms)) {
1158 $whereforadd .= " OR (module='".$this->db->escape($module)."' AND (perms='lire' OR perms='read') AND (subperms IS NULL or subperms = ''))";
1159 }
1160 } else {
1161 // A list of permission was requested (not a single specific permission)
1162 // based on the name of a module of permissions
1163 // Used in the where clause to determine the list of permissions to add.
1164 if (!empty($allmodule)) {
1165 if ($allmodule == 'allmodules') {
1166 $whereforadd = 'allmodules';
1167 } else {
1168 $whereforadd = "module='".$this->db->escape($allmodule)."'";
1169 if (!empty($allperms)) {
1170 $whereforadd .= " AND perms='".$this->db->escape($allperms)."'";
1171 }
1172 }
1173 }
1174 }
1175
1176 // Add automatically other permission using the criteria whereforadd
1177 // $whereforadd can be a SQL filter or the string 'allmodules'
1178 if (!empty($whereforadd)) {
1179 //print "$module-$perms-$subperms";
1180 $sql = "SELECT id";
1181 $sql .= " FROM ".$this->db->prefix()."rights_def";
1182 $sql .= " WHERE entity = ".((int) $entity);
1183 if (!empty($whereforadd) && $whereforadd != 'allmodules') {
1184 $sql .= " AND (".$whereforadd.")"; // Note: parenthesis are important because whereforadd can contains OR. Also note that $whereforadd is already sanitized
1185 }
1186
1187 $sqldelete = "DELETE FROM ".$this->db->prefix()."user_rights";
1188 $sqldelete .= " WHERE fk_user = ".((int) $this->id)." AND fk_id IN (";
1189 $sqldelete .= $sql;
1190 $sqldelete .= ") AND entity = ".((int) $entity);
1191 if (!$this->db->query($sqldelete)) {
1192 $error++;
1193 }
1194
1195 if (!$error) {
1196 $resql = $this->db->query($sql);
1197 if ($resql) {
1198 $num = $this->db->num_rows($resql);
1199 $i = 0;
1200 while ($i < $num) {
1201 $obj = $this->db->fetch_object($resql);
1202
1203 if ($obj) {
1204 $nid = $obj->id;
1205
1206 $sql = "INSERT INTO ".$this->db->prefix()."user_rights (entity, fk_user, fk_id) VALUES (".((int) $entity).", ".((int) $this->id).", ".((int) $nid).")";
1207 if (!$this->db->query($sql)) {
1208 $error++;
1209 }
1210 }
1211
1212 $i++;
1213 }
1214 } else {
1215 $error++;
1216 dol_print_error($this->db);
1217 }
1218 }
1219 }
1220
1221 if (!$error && !$notrigger) {
1222 $langs->load("other");
1223 $this->context = array('audit' => $langs->trans("PermissionsAdd").($rid ? ' (id='.$rid.')' : ''));
1224
1225 // Call trigger
1226 $result = $this->call_trigger('USER_MODIFY', $user);
1227 if ($result < 0) {
1228 $error++;
1229 }
1230 // End call triggers
1231 }
1232
1233 if ($error) {
1234 $this->db->rollback();
1235 return -$error;
1236 } else {
1237 $this->db->commit();
1238 return 1;
1239 }
1240 }
1241
1242
1254 public function delrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
1255 {
1256 global $conf, $user, $langs;
1257
1258 $error = 0;
1259 $wherefordel = '';
1260 $entity = (!empty($entity) ? $entity : $conf->entity);
1261
1262 $this->db->begin();
1263
1264 if (!empty($rid)) {
1265 $module = $perms = $subperms = '';
1266
1267 // When the request is to delete a specific permissions, this gets the
1268 // characteristics for the module, permissions and sub-permission of this permission.
1269 $sql = "SELECT module, perms, subperms";
1270 $sql .= " FROM ".$this->db->prefix()."rights_def";
1271 $sql .= " WHERE id = ".((int) $rid);
1272 $sql .= " AND entity IN (".$this->db->sanitize($entity, 0, 0, 0, 0).")";
1273
1274 $result = $this->db->query($sql);
1275 if ($result) {
1276 $obj = $this->db->fetch_object($result);
1277
1278 if ($obj) {
1279 $module = $obj->module;
1280 $perms = $obj->perms;
1281 $subperms = $obj->subperms;
1282 }
1283 } else {
1284 $error++;
1285 dol_print_error($this->db);
1286 }
1287
1288 // Where clause for the list of permissions to delete
1289 $wherefordel = "id=".((int) $rid);
1290 // Removal of induced rights
1291 if ($subperms == 'lire' || $subperms == 'read') {
1292 $wherefordel .= " OR (module='".$this->db->escape($module)."' AND perms='".$this->db->escape($perms)."' AND subperms IS NOT NULL)";
1293 }
1294 if ($perms == 'lire' || $perms == 'read') {
1295 $wherefordel .= " OR (module='".$this->db->escape($module)."')";
1296 }
1297 } else {
1298 // The deletion of the permissions concerns the name of a module or
1299 // list of permissions.
1300 // Used in the Where clause to determine the list of permission to delete
1301 if (!empty($allmodule)) {
1302 if ($allmodule == 'allmodules') {
1303 $wherefordel = 'allmodules';
1304 } else {
1305 $wherefordel = "module='".$this->db->escape($allmodule)."'";
1306 if (!empty($allperms)) {
1307 $wherefordel .= " AND perms='".$this->db->escape($allperms)."'";
1308 }
1309 }
1310 }
1311 }
1312
1313 // Delete permission according to a criteria set into $wherefordel
1314 if (!empty($wherefordel)) {
1315 //print "$module-$perms-$subperms";
1316 $sql = "SELECT id";
1317 $sql .= " FROM ".$this->db->prefix()."rights_def";
1318 $sql .= " WHERE entity IN (".$this->db->sanitize($entity, 0, 0, 0, 0).")";
1319 if (!empty($wherefordel) && $wherefordel != 'allmodules') {
1320 $sql .= " AND (".$wherefordel.")"; // Note: parenthesis are important because wherefordel can contains OR. Also note that $wherefordel is already sanitized
1321 }
1322
1323 // avoid admin to remove his own important rights
1324 if ($this->admin == 1) {
1325 $sql .= " AND id NOT IN (251, 252, 253, 254, 255, 256)"; // other users rights
1326 $sql .= " AND id NOT IN (341, 342, 343, 344)"; // own rights
1327 $sql .= " AND id NOT IN (351, 352, 353, 354)"; // groups rights
1328 $sql .= " AND id NOT IN (358)"; // user export
1329 }
1330
1331 $sqldelete = "DELETE FROM ".$this->db->prefix()."user_rights";
1332 $sqldelete .= " WHERE fk_user = ".((int) $this->id)." AND fk_id IN (";
1333 $sqldelete .= $sql;
1334 $sqldelete .= ")";
1335 $sqldelete .= " AND entity IN (".$this->db->sanitize($entity, 0, 0, 0, 0).")";
1336
1337 $resql = $this->db->query($sqldelete);
1338 if (!$resql) {
1339 $error++;
1340 dol_print_error($this->db);
1341 }
1342 }
1343
1344 if (!$error && !$notrigger) {
1345 $langs->load("other");
1346 $this->context = array('audit' => $langs->trans("PermissionsDelete").($rid ? ' (id='.$rid.')' : ''));
1347
1348 // Call trigger
1349 $result = $this->call_trigger('USER_MODIFY', $user);
1350 if ($result < 0) {
1351 $error++;
1352 }
1353 // End call triggers
1354 }
1355
1356 if ($error) {
1357 $this->db->rollback();
1358 return -$error;
1359 } else {
1360 $this->db->commit();
1361 return 1;
1362 }
1363 }
1364
1365
1372 public function clearrights()
1373 {
1374 dol_syslog(get_class($this)."::clearrights reset user->rights");
1375 $this->rights = new stdClass();
1376 $this->nb_rights = 0;
1377 $this->all_permissions_are_loaded = 0;
1378 $this->_tab_loaded = array();
1379 }
1380
1381
1390 public function loadRights($moduletag = '', $forcereload = 0)
1391 {
1392 global $conf;
1393
1394 $alreadyloaded = false;
1395
1396 if (empty($forcereload)) {
1397 if ($moduletag && isset($this->_tab_loaded[$moduletag]) && $this->_tab_loaded[$moduletag]) {
1398 // Rights for this module are already loaded, so we leave
1399 $alreadyloaded = true;
1400 }
1401
1402 if (!empty($this->all_permissions_are_loaded)) {
1403 // We already loaded all rights for this user, so we leave
1404 $alreadyloaded = true;
1405 }
1406 }
1407
1408 // More init to avoid warnings/errors
1409 if (!isset($this->rights) || !is_object($this->rights)) {
1410 $this->rights = new stdClass();
1411 }
1412 if (!isset($this->rights->user) || !is_object($this->rights->user)) {
1413 $this->rights->user = new stdClass();
1414 }
1415
1416 // Get permission of users + Get permissions of groups
1417
1418 if (!$alreadyloaded) {
1419 // First user permissions
1420 $sql = "SELECT DISTINCT r.module, r.module_origin, r.perms, r.subperms";
1421 $sql .= " FROM ".$this->db->prefix()."user_rights as ur,";
1422 $sql .= " ".$this->db->prefix()."rights_def as r";
1423 $sql .= " WHERE r.id = ur.fk_id";
1424 if (getDolGlobalString('MULTICOMPANY_BACKWARD_COMPATIBILITY')) {
1425 // On old version, we used entity defined into table r only
1426 // @FIXME Test on MULTICOMPANY_BACKWARD_COMPATIBILITY is a very strange business rules because the select should be always the
1427 // same than into user->loadRights() in user/perms.php and user/group/perms.php
1428 // We should never use and remove this case.
1429 $sql .= " AND r.entity IN (0,".(isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE') ? "1," : "").((int) $conf->entity).")";
1430 } else {
1431 // On table r=rights_def, the unique key is (id, entity) because id is hard coded into module descriptor and inserted during module activation.
1432 // So we must include the filter on entity on both table r. and ur.
1433 $sql .= " AND r.entity = ".((int) $conf->entity)." AND ur.entity = ".((int) $conf->entity);
1434 }
1435 $sql .= " AND ur.fk_user = ".((int) $this->id);
1436 $sql .= " AND r.perms IS NOT NULL";
1437 if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
1438 $sql .= " AND r.perms NOT LIKE '%_advance'"; // Hide advanced perms if option is not enabled
1439 }
1440 if ($moduletag) {
1441 $sql .= " AND r.module = '".$this->db->escape($moduletag)."'";
1442 }
1443
1444 $resql = $this->db->query($sql);
1445 if ($resql) {
1446 $num = $this->db->num_rows($resql);
1447 $i = 0;
1448 while ($i < $num) {
1449 $obj = $this->db->fetch_object($resql);
1450
1451 if ($obj) {
1452 // module_origin (set only when the right was declared by another module
1453 // via KEY_MODULE, to be filed into a foreign module's section of the
1454 // permission grid) is the namespace actually used to check the right with
1455 // hasRight(), so the declaring module keeps control of it regardless of
1456 // which module's section it is grouped under for display.
1457 $module = (!empty($obj->module_origin) ? $obj->module_origin : $obj->module);
1458 $perms = $obj->perms;
1459 $subperms = $obj->subperms;
1460
1461 if (!empty($perms)) {
1462 if (!empty($module)) {
1463 if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
1464 $this->rights->$module = new stdClass();
1465 }
1466 if (!empty($subperms)) {
1467 if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1468 $this->rights->$module->$perms = new stdClass();
1469 }
1470 if (empty($this->rights->$module->$perms->$subperms)) { // if not already counted
1471 $this->nb_rights++;
1472 }
1473 $this->rights->$module->$perms->$subperms = 1;
1474 } else {
1475 if (empty($this->rights->$module->$perms)) { // if not already counted
1476 $this->nb_rights++;
1477 }
1478 $this->rights->$module->$perms = 1;
1479 }
1480 }
1481 }
1482 }
1483 $i++;
1484 }
1485 $this->db->free($resql);
1486 }
1487
1488 // Now permissions of groups
1489 $sql = "SELECT DISTINCT r.module, r.module_origin, r.perms, r.subperms, r.entity";
1490 $sql .= " FROM ".$this->db->prefix()."usergroup_rights as gr,";
1491 $sql .= " ".$this->db->prefix()."usergroup_user as gu,";
1492 $sql .= " ".$this->db->prefix()."rights_def as r";
1493 $sql .= " WHERE r.id = gr.fk_id";
1494 if (getDolGlobalString('MULTICOMPANY_BACKWARD_COMPATIBILITY')) {
1495 // @FIXME Test on MULTICOMPANY_BACKWARD_COMPATIBILITY is a very strange business rules because the select should be always the
1496 // same than into user->loadRights() in user/perms.php and user/group/perms.php
1497 // We should never use and remove this case.
1498 if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
1499 $sql .= " AND gu.entity IN (0,".((int) $conf->entity).")";
1500 } else {
1501 $sql .= " AND r.entity = ".((int) $conf->entity);
1502 }
1503 } else {
1504 $sql .= " AND gr.entity = ".((int) $conf->entity); // Only groups created in current entity
1505 // The entity on the table gu=usergroup_user should be useless and should never be used because it is already into gr and r.
1506 // but when using MULTICOMPANY_TRANSVERSE_MODE, we may have inserted record that make rubbish result here due to the duplicate record of
1507 // other entities, so we are forced to add a filter on gu here
1508 $sql .= " AND gu.entity IN (0,".((int) $conf->entity).")";
1509 $sql .= " AND r.entity = ".((int) $conf->entity); // Only permission of modules enabled in current entity
1510 }
1511 // End of strange business rule
1512 $sql .= " AND gr.fk_usergroup = gu.fk_usergroup";
1513 $sql .= " AND gu.fk_user = ".((int) $this->id);
1514 $sql .= " AND r.perms IS NOT NULL";
1515 if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
1516 $sql .= " AND r.perms NOT LIKE '%_advance'"; // Hide advanced perms if option is not enabled
1517 }
1518 if ($moduletag) {
1519 $sql .= " AND r.module = '".$this->db->escape($moduletag)."'";
1520 }
1521
1522 $resql = $this->db->query($sql);
1523 if ($resql) {
1524 $num = $this->db->num_rows($resql);
1525 $i = 0;
1526 while ($i < $num) {
1527 $obj = $this->db->fetch_object($resql);
1528
1529 if ($obj) {
1530 // module_origin (set only when the right was declared by another module
1531 // via KEY_MODULE, to be filed into a foreign module's section of the
1532 // permission grid) is the namespace actually used to check the right with
1533 // hasRight(), so the declaring module keeps control of it regardless of
1534 // which module's section it is grouped under for display.
1535 $module = (!empty($obj->module_origin) ? $obj->module_origin : $obj->module);
1536 $perms = $obj->perms;
1537 $subperms = $obj->subperms;
1538
1539 if (!empty($perms)) {
1540 if (!empty($module)) {
1541 if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
1542 $this->rights->$module = new stdClass();
1543 }
1544 if (!empty($subperms)) {
1545 if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1546 $this->rights->$module->$perms = new stdClass();
1547 }
1548 if (empty($this->rights->$module->$perms->$subperms)) { // if not already counted
1549 $this->nb_rights++;
1550 }
1551 $this->rights->$module->$perms->$subperms = 1;
1552 } else {
1553 // if we have already define a subperm like this $this->rights->$module->level1->level2 with llx_user_rights, we don't want override level1 because the level2 can be not define on user group
1554 if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1555 if (empty($this->rights->$module->$perms)) { // if not already counted
1556 $this->nb_rights++;
1557 }
1558 $this->rights->$module->$perms = 1;
1559 }
1560 }
1561 }
1562 }
1563 }
1564 $i++;
1565 }
1566 $this->db->free($resql);
1567 }
1568
1569 // Force permission on user for admin
1570 if (!empty($this->admin)) {
1571 if (empty($this->rights->user->user)) {
1572 $this->rights->user->user = new stdClass();
1573 }
1574 $listofpermtotest = array('lire', 'creer', 'password', 'supprimer', 'export');
1575 foreach ($listofpermtotest as $permtotest) {
1576 if (empty($this->rights->user->user->$permtotest)) {
1577 $this->rights->user->user->$permtotest = 1;
1578 $this->nb_rights++;
1579 }
1580 }
1581 if (empty($this->rights->user->self)) {
1582 $this->rights->user->self = new stdClass();
1583 }
1584 $listofpermtotest = array('creer', 'password');
1585 foreach ($listofpermtotest as $permtotest) {
1586 if (empty($this->rights->user->self->$permtotest)) {
1587 $this->rights->user->self->$permtotest = 1;
1588 $this->nb_rights++;
1589 }
1590 }
1591 // Add test on advanced permissions
1592 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
1593 if (empty($this->rights->user->user_advance)) {
1594 $this->rights->user->user_advance = new stdClass();
1595 }
1596 $listofpermtotest = array('readperms', 'write');
1597 foreach ($listofpermtotest as $permtotest) {
1598 if (empty($this->rights->user->user_advance->$permtotest)) {
1599 $this->rights->user->user_advance->$permtotest = 1;
1600 $this->nb_rights++;
1601 }
1602 }
1603 if (empty($this->rights->user->self_advance)) {
1604 $this->rights->user->self_advance = new stdClass();
1605 }
1606 $listofpermtotest = array('readperms', 'writeperms');
1607 foreach ($listofpermtotest as $permtotest) {
1608 if (empty($this->rights->user->self_advance->$permtotest)) {
1609 $this->rights->user->self_advance->$permtotest = 1;
1610 $this->nb_rights++;
1611 }
1612 }
1613 if (empty($this->rights->user->group_advance)) {
1614 $this->rights->user->group_advance = new stdClass();
1615 }
1616 $listofpermtotest = array('read', 'readperms', 'write', 'delete');
1617 foreach ($listofpermtotest as $permtotest) {
1618 if (empty($this->rights->user) || empty($this->rights->user->group_advance->$permtotest)) {
1619 $this->rights->user->group_advance->$permtotest = 1;
1620 $this->nb_rights++;
1621 }
1622 }
1623 }
1624 }
1625
1626 // For backward compatibility
1627 if (isset($this->rights->propale) && !isset($this->rights->propal)) {
1628 $this->rights->propal = $this->rights->propale;
1629 }
1630 if (isset($this->rights->propal) && !isset($this->rights->propale)) {
1631 $this->rights->propale = $this->rights->propal;
1632 }
1633
1634 if (!$moduletag) {
1635 // If the module was not define, then everything is loaded.
1636 // Therefore, we can consider that the permissions are cached
1637 // because they were all loaded for this user instance.
1638 $this->all_permissions_are_loaded = 1;
1639 } else {
1640 // If the module is defined, we flag it as loaded into cache
1641 $this->_tab_loaded[$moduletag] = 1;
1642 }
1643 }
1644 }
1645
1658 public function getrights($moduletag = '', $forcereload = 0)
1659 {
1660 $this->loadRights($moduletag, $forcereload);
1661 }
1662
1669 public function setstatus($status)
1670 {
1671 global $conf, $langs, $user;
1672
1673 $error = 0;
1674
1675 // Check parameters
1676 if (isset($this->status)) {
1677 if ($this->status == $status) {
1678 return 0;
1679 }
1680 } elseif (isset($this->statut) && $this->statut == $status) { // $this->statut is deprecated
1681 return 0;
1682 }
1683
1684 $this->db->begin();
1685
1686 // Save in database
1687 $sql = "UPDATE ".$this->db->prefix()."user";
1688 $sql .= " SET statut = ".((int) $status);
1689 $sql .= " WHERE rowid = ".((int) $this->id);
1690 $result = $this->db->query($sql);
1691
1692 dol_syslog(get_class($this)."::setstatus", LOG_DEBUG);
1693 if ($result) {
1694 if ($status == 0) {
1695 $this->context['actionmsg'] = 'User '.$this->login.' disabled';
1696 } else {
1697 $this->context['actionmsg'] = 'User '.$this->login.' enabled';
1698 }
1699 // Call trigger
1700 $result = $this->call_trigger('USER_ENABLEDISABLE', $user);
1701 if ($result < 0) {
1702 $error++;
1703 }
1704 // End call triggers
1705 }
1706
1707 if ($error) {
1708 $this->db->rollback();
1709 return -$error;
1710 } else {
1711 $this->status = $status;
1712 $this->statut = $status;
1713 $this->db->commit();
1714 return 1;
1715 }
1716 }
1717
1725 public function setForcePasswordChange($user, $value)
1726 {
1727 $error = 0;
1728
1729 $value = (int) $value;
1730
1731 // Check parameters : no change short line
1732 if ($this->force_pass_change == $value) {
1733 return 0;
1734 }
1735
1736 $this->db->begin();
1737
1738 // Save in database
1739 $sql = "UPDATE ".$this->db->prefix()."user";
1740 $sql .= " SET force_pass_change = ".((int) $value);
1741 $sql .= " WHERE rowid = ".((int) $this->id);
1742 $result = $this->db->query($sql);
1743
1744 dol_syslog(get_class($this)."::setForcePasswordChange", LOG_DEBUG);
1745 if ($result) {
1746 $this->force_pass_change = $value;
1747 // Call trigger
1748 $result = $this->call_trigger('USER_MODIFY', $user);
1749 if ($result < 0) {
1750 $error++;
1751 }
1752 // End call triggers
1753 } else {
1754 $error++;
1755 $this->error = $this->db->lasterror();
1756 }
1757
1758 if ($error) {
1759 $this->db->rollback();
1760 return -$error;
1761 } else {
1762 $this->db->commit();
1763 return 1;
1764 }
1765 }
1766
1777 public function setCategories($categories)
1778 {
1779 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1780 return parent::setCategoriesCommon($categories, Categorie::TYPE_USER);
1781 }
1782
1789 public function delete(User $user)
1790 {
1791 $error = 0;
1792
1793 $this->db->begin();
1794
1795 $this->fetch($this->id);
1796
1797 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1798
1799 // Remove rights
1800 $sql = "DELETE FROM ".$this->db->prefix()."user_rights WHERE fk_user = ".((int) $this->id);
1801
1802 if (!$error && !$this->db->query($sql)) {
1803 $error++;
1804 $this->error = $this->db->lasterror();
1805 }
1806
1807 // Remove group
1808 $sql = "DELETE FROM ".$this->db->prefix()."usergroup_user WHERE fk_user = ".((int) $this->id);
1809 if (!$error && !$this->db->query($sql)) {
1810 $error++;
1811 $this->error = $this->db->lasterror();
1812 }
1813
1814 // Remove params
1815 $sql = "DELETE FROM ".$this->db->prefix()."user_param WHERE fk_user = ".((int) $this->id);
1816 if (!$error && !$this->db->query($sql)) {
1817 $error++;
1818 $this->error = $this->db->lasterror();
1819 }
1820
1821 // If contact, remove link
1822 if ($this->contact_id > 0) {
1823 $sql = "UPDATE ".$this->db->prefix()."socpeople SET fk_user_creat = null WHERE rowid = ".((int) $this->contact_id);
1824 if (!$error && !$this->db->query($sql)) {
1825 $error++;
1826 $this->error = $this->db->lasterror();
1827 }
1828 }
1829
1830 // Remove extrafields
1831 if (!$error) {
1832 $result = $this->deleteExtraFields();
1833 if ($result < 0) {
1834 $error++;
1835 dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1836 }
1837 }
1838
1839 // Remove user
1840 if (!$error) {
1841 $sql = "DELETE FROM ".$this->db->prefix()."user WHERE rowid = ".((int) $this->id);
1842 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1843 if (!$this->db->query($sql)) {
1844 $error++;
1845 $this->error = $this->db->lasterror();
1846 }
1847 }
1848
1849 if (!$error) {
1850 // Call trigger
1851 $result = $this->call_trigger('USER_DELETE', $user);
1852 if ($result < 0) {
1853 $error++;
1854 $this->db->rollback();
1855 return -1;
1856 }
1857 // End call triggers
1858
1859 $this->db->commit();
1860 return 1;
1861 } else {
1862 $this->db->rollback();
1863 return -1;
1864 }
1865 }
1866
1874 public function create($user, $notrigger = 0)
1875 {
1876 global $conf, $langs;
1877 global $mysoc;
1878
1879 // Clean parameters
1880 $this->setUpperOrLowerCase();
1881
1882 $this->civility_code = trim((string) $this->civility_code);
1883 $this->login = trim((string) $this->login);
1884 $this->user_creation_id = (int) $user->id;
1885 if (!isset($this->entity)) {
1886 $this->entity = $conf->entity; // If not defined, we use default value
1887 }
1888 dol_syslog(get_class($this)."::create login=".$this->login.", user=".(is_object($user) ? $user->id : ''), LOG_DEBUG);
1889
1890 $badCharUnauthorizedIntoLoginName = getDolGlobalLoginBadCharUnauthorized();
1891
1892 // Check parameters
1893 if (getDolGlobalString('USER_MAIL_REQUIRED') && !isValidEmail($this->email)) {
1894 $langs->load("errors");
1895 $this->error = $langs->trans("ErrorBadEMail", $this->email);
1896 return -1;
1897 }
1898 if (empty($this->login)) {
1899 $langs->load("errors");
1900 $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Login"));
1901 return -1;
1902 } elseif ($badCharUnauthorizedIntoLoginName !== '' && preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) {
1903 $langs->load("errors");
1904 $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login"));
1905 return -1;
1906 }
1907
1908 $this->datec = dol_now();
1909
1910 $error = 0;
1911 $this->db->begin();
1912
1913 // Check if login already exists in same entity or into entity 0.
1914 if ($this->login) {
1915 $sqltochecklogin = "SELECT COUNT(*) as nb FROM ".$this->db->prefix()."user WHERE entity IN (".$this->db->sanitize(((int) $this->entity).", 0").") AND login = '".$this->db->escape($this->login)."'";
1916 $resqltochecklogin = $this->db->query($sqltochecklogin);
1917 if ($resqltochecklogin) {
1918 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
1919 if ($objtochecklogin && $objtochecklogin->nb > 0) {
1920 $langs->load("errors");
1921 $this->error = $langs->trans("ErrorLoginAlreadyExists", $this->login);
1922 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
1923 $this->db->rollback();
1924 return -6;
1925 }
1926 $this->db->free($resqltochecklogin);
1927 }
1928 }
1929 if (!empty($this->email)) {
1930 $sqltochecklogin = "SELECT COUNT(*) as nb FROM ".$this->db->prefix()."user WHERE entity IN (".$this->db->sanitize(((int) $this->entity).", 0").") AND email = '".$this->db->escape($this->email)."'";
1931 $resqltochecklogin = $this->db->query($sqltochecklogin);
1932 if ($resqltochecklogin) {
1933 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
1934 if ($objtochecklogin && $objtochecklogin->nb > 0) {
1935 $langs->load("errors");
1936 $this->error = $langs->trans("ErrorEmailAlreadyExists", $this->email);
1937 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
1938 $this->db->rollback();
1939 return -6;
1940 }
1941 $this->db->free($resqltochecklogin);
1942 }
1943 }
1944
1945 // Insert into database
1946 $sql = "INSERT INTO ".$this->db->prefix()."user (datec, login, ldap_sid, fk_user_creat, entity)";
1947 $sql .= " VALUES('".$this->db->idate($this->datec)."', '".$this->db->escape($this->login)."', '".$this->db->escape($this->ldap_sid)."', ".(int) $this->user_creation_id.", ".((int) $this->entity).")";
1948 $result = $this->db->query($sql);
1949
1950 dol_syslog(get_class($this)."::create", LOG_DEBUG);
1951 if ($result) {
1952 $this->id = $this->db->last_insert_id($this->db->prefix()."user");
1953
1954 // Set default rights
1955 if ($this->set_default_rights() < 0) {
1956 $this->error = 'ErrorFailedToSetDefaultRightOfUser';
1957 $this->db->rollback();
1958 return -5;
1959 }
1960
1961 if (getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && getDolGlobalString('STOCK_USERSTOCK_AUTOCREATE')) {
1962 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
1963 $langs->load("stocks");
1964
1965 $entrepot = new Entrepot($this->db);
1966 $entrepot->label = $langs->trans("PersonalStock", $this->getFullName($langs));
1967 $entrepot->libelle = $entrepot->label; // For backward compatibility
1968 $entrepot->description = $langs->trans("ThisWarehouseIsPersonalStock", $this->getFullName($langs));
1969 $entrepot->statut = 1;
1970 $entrepot->country_id = $mysoc->country_id;
1971
1972 $warehouseid = $entrepot->create($user);
1973
1974 $this->fk_warehouse = $warehouseid;
1975 }
1976
1977 // Update minor fields
1978 $result = $this->update($user, 1, 1);
1979 if ($result < 0) {
1980 $this->db->rollback();
1981 return -4;
1982 }
1983
1984 if (!$notrigger) {
1985 // Call trigger
1986 $result = $this->call_trigger('USER_CREATE', $user);
1987 if ($result < 0) {
1988 $error++;
1989 }
1990 // End call triggers
1991 }
1992
1993 if (!$error) {
1994 $this->db->commit();
1995 return $this->id;
1996 } else {
1997 //$this->error=$interface->error;
1998 dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
1999 $this->db->rollback();
2000 return -3;
2001 }
2002 } else {
2003 $this->error = $this->db->lasterror();
2004 $this->db->rollback();
2005 return -2;
2006 }
2007 }
2008
2009
2010 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2019 public function create_from_contact($contact, $login = '', $password = '')
2020 {
2021 // phpcs:enable
2022 global $user;
2023
2024 $error = 0;
2025
2026 // Define parameters
2027 $this->admin = 0;
2028 $this->civility_code = $contact->civility_code;
2029 $this->lastname = $contact->lastname;
2030 $this->firstname = $contact->firstname;
2031 //$this->gender = $contact->gender; // contact has no gender
2032 $this->email = $contact->email;
2033 $this->socialnetworks = $contact->socialnetworks;
2034 $this->office_phone = $contact->phone_pro;
2035 $this->office_fax = $contact->fax;
2036 $this->user_mobile = $contact->phone_mobile;
2037 $this->address = $contact->address;
2038 $this->zip = $contact->zip;
2039 $this->town = $contact->town;
2040 $this->setUpperOrLowerCase();
2041 $this->state_id = $contact->state_id;
2042 $this->country_id = $contact->country_id;
2043 $this->employee = 0;
2044
2045 if (empty($login)) {
2046 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
2047 $login = dol_buildlogin($contact->lastname, $contact->firstname);
2048 }
2049 $this->login = $login;
2050
2051 $this->db->begin();
2052
2053 // Create user and set $this->id. Trigger is disabled because executed later.
2054 $result = $this->create($user, 1);
2055 if ($result > 0) {
2056 $sql = "UPDATE ".$this->db->prefix()."user";
2057 $sql .= " SET fk_socpeople=".((int) $contact->id);
2058 $sql .= ", civility='".$this->db->escape($contact->civility_code)."'";
2059 if ($contact->socid > 0) {
2060 $sql .= ", fk_soc=".((int) $contact->socid);
2061 }
2062 $sql .= " WHERE rowid=".((int) $this->id);
2063
2064 $resql = $this->db->query($sql);
2065
2066 dol_syslog(get_class($this)."::create_from_contact", LOG_DEBUG);
2067 if ($resql) {
2068 $this->context['createfromcontact'] = 'createfromcontact';
2069
2070 // Call trigger
2071 $result = $this->call_trigger('USER_CREATE', $user);
2072 if ($result < 0) {
2073 $error++;
2074 $this->db->rollback();
2075 return -1;
2076 }
2077 // End call triggers
2078
2079 $this->db->commit();
2080 return $this->id;
2081 } else {
2082 $this->error = $this->db->error();
2083
2084 $this->db->rollback();
2085 return -1;
2086 }
2087 } else {
2088 // $this->error already set
2089 dol_syslog(get_class($this)."::create_from_contact - 0");
2090
2091 $this->db->rollback();
2092 return $result;
2093 }
2094 }
2095
2096 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2105 public function create_from_member($member, $login = '')
2106 {
2107 // phpcs:enable
2108 global $user;
2109
2110 // Set properties on new user
2111 $this->admin = 0;
2112 $this->civility_code = $member->civility_code;
2113 $this->lastname = $member->lastname;
2114 $this->firstname = $member->firstname;
2115 $this->gender = $member->gender;
2116 $this->email = $member->email;
2117 $this->fk_member = $member->id;
2118 $this->address = $member->address;
2119 $this->zip = $member->zip;
2120 $this->town = $member->town;
2121 $this->setUpperOrLowerCase();
2122 $this->state_id = $member->state_id;
2123 $this->country_id = $member->country_id;
2124 $this->socialnetworks = $member->socialnetworks;
2125
2126 $this->pass = $member->pass;
2127 $this->pass_crypted = $member->pass_indatabase_crypted;
2128
2129 if (empty($login)) {
2130 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
2131 $login = dol_buildlogin($member->lastname, $member->firstname);
2132 }
2133 $this->login = $login;
2134
2135 $this->db->begin();
2136
2137 // Create and set $this->id
2138 $result = $this->create($user);
2139 if ($result > 0) {
2140 if (!empty($this->pass)) { // If a clear password was received (this situation should not happen anymore now), we use it to save it into database
2141 $newpass = $this->setPassword($user, $this->pass);
2142 if (is_int($newpass) && $newpass < 0) {
2143 $result = -2;
2144 }
2145 } elseif (!empty($this->pass_crypted)) { // If an encrypted password is already known, we save it directly into database because the previous create did not save it.
2146 $sql = "UPDATE ".$this->db->prefix()."user";
2147 $sql .= " SET pass_crypted = '".$this->db->escape($this->pass_crypted)."'";
2148 $sql .= " WHERE rowid=".((int) $this->id);
2149
2150 $resql = $this->db->query($sql);
2151 if (!$resql) {
2152 $result = -1;
2153 }
2154 }
2155
2156 if ($result > 0 && $member->socid) { // If member is linked to a thirdparty
2157 $sql = "UPDATE ".$this->db->prefix()."user";
2158 $sql .= " SET fk_soc=".((int) $member->socid);
2159 $sql .= " WHERE rowid=".((int) $this->id);
2160
2161 dol_syslog(get_class($this)."::create_from_member", LOG_DEBUG);
2162 $resql = $this->db->query($sql);
2163 if ($resql) {
2164 $this->db->commit();
2165 return $this->id;
2166 } else {
2167 $this->error = $this->db->lasterror();
2168
2169 $this->db->rollback();
2170 return -1;
2171 }
2172 }
2173 }
2174
2175 if ($result > 0) {
2176 $this->db->commit();
2177 return $this->id;
2178 } else {
2179 // $this->error was already set
2180 $this->db->rollback();
2181 return -2;
2182 }
2183 }
2184
2185 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2191 public function set_default_rights()
2192 {
2193 // phpcs:enable
2194 global $conf;
2195
2196 $rd = array();
2197 $num = 0;
2198 $sql = "SELECT id FROM ".$this->db->prefix()."rights_def";
2199 $sql .= " WHERE bydefault = 1";
2200 $sql .= " AND entity = ".((int) $conf->entity);
2201
2202 $resql = $this->db->query($sql);
2203 if ($resql) {
2204 $num = $this->db->num_rows($resql);
2205 $i = 0;
2206 while ($i < $num) {
2207 $row = $this->db->fetch_row($resql);
2208 $rd[$i] = $row[0];
2209 $i++;
2210 }
2211 $this->db->free($resql);
2212 }
2213 $i = 0;
2214 while ($i < $num) {
2215 $sql = "DELETE FROM ".$this->db->prefix()."user_rights WHERE fk_user = ".((int) $this->id)." AND fk_id=".((int) $rd[$i]);
2216 $result = $this->db->query($sql);
2217
2218 $sql = "INSERT INTO ".$this->db->prefix()."user_rights (fk_user, fk_id) VALUES (".((int) $this->id).", ".((int) $rd[$i]).")";
2219 $result = $this->db->query($sql);
2220 if (!$result) {
2221 return -1;
2222 }
2223 $i++;
2224 }
2225
2226 return $i;
2227 }
2228
2239 public function update($user, $notrigger = 0, $nosyncmember = 0, $nosyncmemberpass = 0, $nosynccontact = 0)
2240 {
2241 global $langs;
2242
2243 if (empty($this->country_id) && !empty($this->country_code)) {
2244 $country_id = getCountry($this->country_code, '3');
2245 $this->country_id = is_int($country_id) ? $country_id : 0;
2246 }
2247
2248 $nbrowsaffected = 0;
2249 $error = 0;
2250
2251 dol_syslog(get_class($this)."::update notrigger=".$notrigger.", nosyncmember=".$nosyncmember.", nosyncmemberpass=".$nosyncmemberpass);
2252
2253 // Clean parameters
2254 $this->civility_code = trim((string) $this->civility_code);
2255 $this->lastname = trim((string) $this->lastname);
2256 $this->firstname = trim((string) $this->firstname);
2257 $this->ref_employee = trim((string) $this->ref_employee);
2258 $this->national_registration_number = trim((string) $this->national_registration_number);
2259 $this->employee = ($this->employee > 0 ? $this->employee : 0);
2260 $this->login = trim((string) $this->login);
2261 $this->gender = trim((string) $this->gender);
2262
2263 $this->pass = trim((string) $this->pass);
2264 $this->api_key = trim((string) $this->api_key);
2265 $this->datestartvalidity = empty($this->datestartvalidity) ? '' : $this->datestartvalidity;
2266 $this->dateendvalidity = empty($this->dateendvalidity) ? '' : $this->dateendvalidity;
2267
2268 $this->address = trim((string) $this->address);
2269 $this->zip = trim((string) $this->zip);
2270 $this->town = trim((string) $this->town);
2271
2272 $this->state_id = ($this->state_id > 0 ? $this->state_id : 0);
2273 $this->country_id = ($this->country_id > 0 ? $this->country_id : 0);
2274 $this->office_phone = trim((string) $this->office_phone);
2275 $this->office_fax = trim((string) $this->office_fax);
2276 $this->user_mobile = trim((string) $this->user_mobile);
2277 $this->personal_mobile = trim((string) $this->personal_mobile);
2278 $this->email = trim((string) $this->email);
2279 $this->personal_email = trim((string) $this->personal_email);
2280
2281 $this->job = trim((string) $this->job);
2282 $this->signature = trim((string) $this->signature);
2283 $this->note_public = trim((string) $this->note_public);
2284 $this->note_private = trim((string) $this->note_private);
2285 $this->openid = trim((string) $this->openid);
2286 $this->admin = ($this->admin > 0 ? $this->admin : 0);
2287 $this->user_modification_id = $user->id;
2288
2289 $this->accountancy_code_user_general = trim((string) $this->accountancy_code_user_general);
2290 $this->accountancy_code = trim((string) $this->accountancy_code);
2291 $this->color = trim(str_replace('#', '', (string) $this->color));
2292 $this->dateemployment = empty($this->dateemployment) ? '' : $this->dateemployment;
2293 $this->dateemploymentend = empty($this->dateemploymentend) ? '' : $this->dateemploymentend;
2294
2295 $this->birth = empty($this->birth) ? '' : $this->birth;
2296 $this->fk_warehouse = (int) $this->fk_warehouse;
2297 $this->fk_establishment = (int) $this->fk_establishment;
2298
2299 $this->setUpperOrLowerCase();
2300
2301 // Check parameters
2302 $badCharUnauthorizedIntoLoginName = getDolGlobalLoginBadCharUnauthorized();
2303
2304 if (getDolGlobalString('USER_MAIL_REQUIRED') && !isValidEmail($this->email)) {
2305 $langs->load("errors");
2306 $this->error = $langs->trans("ErrorBadEMail", $this->email);
2307 return -1;
2308 }
2309 if (empty($this->login)) {
2310 $langs->load("errors");
2311 $this->error = $langs->trans("ErrorFieldRequired", 'Login');
2312 return -1;
2313 } elseif ($badCharUnauthorizedIntoLoginName !== '' && preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) {
2314 $langs->load("errors");
2315 $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login"));
2316 return -1;
2317 }
2318
2319 $this->db->begin();
2320
2321 // Check if login already exists in same entity or into entity 0.
2322 if (is_object($this->oldcopy) && !empty($this->oldcopy->id) && $this->oldcopy->login != $this->login) {
2323 $sqltochecklogin = "SELECT COUNT(*) as nb FROM ".$this->db->prefix()."user WHERE entity IN (".$this->db->sanitize(((int) $this->entity).", 0").") AND login = '".$this->db->escape($this->login)."'";
2324 $resqltochecklogin = $this->db->query($sqltochecklogin);
2325 if ($resqltochecklogin) {
2326 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
2327 if ($objtochecklogin && $objtochecklogin->nb > 0) {
2328 $langs->load("errors");
2329 $this->error = $langs->trans("ErrorLoginAlreadyExists", $this->login);
2330 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
2331 $this->db->rollback();
2332 return -1;
2333 }
2334 }
2335 }
2336 if (is_object($this->oldcopy) && !empty($this->oldcopy->id) && !empty($this->email) && $this->oldcopy->email != $this->email) {
2337 $sqltochecklogin = "SELECT COUNT(*) as nb FROM ".$this->db->prefix()."user WHERE entity IN (".$this->db->sanitize(((int) $this->entity).", 0").") AND email = '".$this->db->escape($this->email)."'";
2338 $resqltochecklogin = $this->db->query($sqltochecklogin);
2339 if ($resqltochecklogin) {
2340 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
2341 if ($objtochecklogin && $objtochecklogin->nb > 0) {
2342 $langs->load("errors");
2343 $this->error = $langs->trans("ErrorEmailAlreadyExists", $this->email);
2344 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
2345 $this->db->rollback();
2346 return -1;
2347 }
2348 }
2349 }
2350
2351 // Update data
2352 $sql = "UPDATE ".$this->db->prefix()."user SET";
2353 $sql .= " civility = '".$this->db->escape($this->civility_code)."'";
2354 $sql .= ", lastname = '".$this->db->escape($this->lastname)."'";
2355 $sql .= ", firstname = '".$this->db->escape($this->firstname)."'";
2356 $sql .= ", ref_employee = '".$this->db->escape($this->ref_employee)."'";
2357 $sql .= ", national_registration_number = '".$this->db->escape($this->national_registration_number)."'";
2358 $sql .= ", employee = ".(int) $this->employee;
2359 $sql .= ", login = '".$this->db->escape($this->login)."'";
2360 $sql .= ", api_key = ".($this->api_key ? "'".$this->db->escape(dolEncrypt($this->api_key, '', '', 'dolibarr'))."'" : "null");
2361 $sql .= ", gender = ".($this->gender != -1 ? "'".$this->db->escape($this->gender)."'" : "null"); // 'man' or 'woman' or 'other'
2362 $sql .= ", birth=".(strval($this->birth) != '' ? "'".$this->db->idate($this->birth, 'tzserver')."'" : 'null');
2363 if (!empty($user->admin)) {
2364 $sql .= ", admin = ".(int) $this->admin; // admin flag can be set/unset only by an admin user
2365 }
2366 $sql .= ", address = '".$this->db->escape($this->address)."'";
2367 $sql .= ", zip = '".$this->db->escape($this->zip)."'";
2368 $sql .= ", town = '".$this->db->escape($this->town)."'";
2369 $sql .= ", fk_state = ".((!empty($this->state_id) && $this->state_id > 0) ? ((int) $this->state_id) : "null");
2370 $sql .= ", fk_country = ".((!empty($this->country_id) && $this->country_id > 0) ? ((int) $this->country_id) : "null");
2371 $sql .= ", office_phone = '".$this->db->escape($this->office_phone)."'";
2372 $sql .= ", office_fax = '".$this->db->escape($this->office_fax)."'";
2373 $sql .= ", user_mobile = '".$this->db->escape($this->user_mobile)."'";
2374 $sql .= ", personal_mobile = '".$this->db->escape($this->personal_mobile)."'";
2375 $sql .= ", email = '".$this->db->escape($this->email)."'";
2376 $sql .= ", personal_email = '".$this->db->escape($this->personal_email)."'";
2377 $sql .= ", socialnetworks = '".$this->db->escape(json_encode($this->socialnetworks))."'";
2378 $sql .= ", job = '".$this->db->escape($this->job)."'";
2379 $sql .= ", signature = '".$this->db->escape($this->signature)."'";
2380 $sql .= ", accountancy_code_user_general = '".$this->db->escape($this->accountancy_code_user_general)."'";
2381 $sql .= ", accountancy_code = '".$this->db->escape($this->accountancy_code)."'";
2382 $sql .= ", color = '".$this->db->escape($this->color)."'";
2383 $sql .= ", dateemployment=".(strval($this->dateemployment) != '' ? "'".$this->db->idate($this->dateemployment)."'" : 'null');
2384 $sql .= ", dateemploymentend=".(strval($this->dateemploymentend) != '' ? "'".$this->db->idate($this->dateemploymentend)."'" : 'null');
2385 $sql .= ", datestartvalidity=".(strval($this->datestartvalidity) != '' ? "'".$this->db->idate($this->datestartvalidity)."'" : 'null');
2386 $sql .= ", dateendvalidity=".(strval($this->dateendvalidity) != '' ? "'".$this->db->idate($this->dateendvalidity)."'" : 'null');
2387 $sql .= ", note_private = '".$this->db->escape($this->note_private)."'";
2388 $sql .= ", note_public = '".$this->db->escape($this->note_public)."'";
2389 $sql .= ", photo = ".($this->photo ? "'".$this->db->escape($this->photo)."'" : "null");
2390 $sql .= ", openid = ".($this->openid ? "'".$this->db->escape($this->openid)."'" : "null");
2391 $sql .= ", fk_user = ".($this->fk_user > 0 ? ((int) $this->fk_user) : "null");
2392 $sql .= ", fk_user_modif = ".($this->user_modification_id > 0 ? ((int) $this->user_modification_id) : "null");
2393 $sql .= ", fk_user_expense_validator = ".($this->fk_user_expense_validator > 0 ? ((int) $this->fk_user_expense_validator) : "null");
2394 $sql .= ", fk_user_holiday_validator = ".($this->fk_user_holiday_validator > 0 ? ((int) $this->fk_user_holiday_validator) : "null");
2395 if (isset($this->thm) || $this->thm != '') {
2396 $sql .= ", thm= ".($this->thm != '' ? "'".$this->db->escape($this->thm)."'" : "null");
2397 }
2398 if (isset($this->tjm) || $this->tjm != '') {
2399 $sql .= ", tjm= ".($this->tjm != '' ? "'".$this->db->escape($this->tjm)."'" : "null");
2400 }
2401 if (isset($this->salary) || $this->salary != '') {
2402 $sql .= ", salary= ".($this->salary != '' ? "'".$this->db->escape($this->salary)."'" : "null");
2403 }
2404 if (isset($this->salaryextra) || $this->salaryextra != '') {
2405 $sql .= ", salaryextra= ".($this->salaryextra != '' ? "'".$this->db->escape($this->salaryextra)."'" : "null");
2406 }
2407 $sql .= ", weeklyhours= ".($this->weeklyhours != '' ? "'".$this->db->escape($this->weeklyhours)."'" : "null");
2408 if (isModEnabled('multicompany') && !empty($user->admin) && empty($user->entity) && $user->id != $this->id) {
2409 // entity flag can be set/unset only by another superadmin user, and only when multicompany is enabled.
2410 // Without multicompany, entity must never be written here: fetch() forces an admin's entity to 0 in memory
2411 // (an admin is a global admin without multicompany), and persisting that would wrongly turn the user into
2412 // a "whole database" (entity 0) admin.
2413 $sql .= ", entity = ".((int) $this->entity);
2414 }
2415
2416 $sql .= ", default_range = ".($this->default_range > 0 ? ((int) $this->default_range) : 'null');
2417 $sql .= ", default_c_exp_tax_cat = ".($this->default_c_exp_tax_cat > 0 ? ((int) $this->default_c_exp_tax_cat) : 'null');
2418 $sql .= ", fk_warehouse = ".($this->fk_warehouse > 0 ? ((int) $this->fk_warehouse) : "null");
2419 $sql .= ", fk_establishment = ".($this->fk_establishment > 0 ? ((int) $this->fk_establishment) : "null");
2420 $sql .= ", lang = ".($this->lang ? "'".$this->db->escape($this->lang)."'" : "null");
2421 $sql .= ", force_pass_change = ".($this->force_pass_change ? ((int) $this->force_pass_change) : "0");
2422 $sql .= " WHERE rowid = ".((int) $this->id);
2423
2424 dol_syslog(get_class($this)."::update", LOG_DEBUG);
2425 $resql = $this->db->query($sql);
2426 if ($resql) {
2427 $nbrowsaffected += $this->db->affected_rows($resql);
2428
2429 // Update password
2430 if (!empty($this->pass)) {
2431 if ($this->pass != $this->pass_indatabase && !dol_verifyHash($this->pass, $this->pass_indatabase_crypted)) {
2432 // If a new value for password is set and different than the one encrypted into database
2433 $result = $this->setPassword($user, $this->pass, 0, $notrigger, $nosyncmemberpass, 0, 1);
2434 if (is_int($result) && $result < 0) {
2435 return -5;
2436 }
2437 }
2438 }
2439
2440 // If user is linked to a member, remove old link to this member
2441 if ($this->fk_member > 0) {
2442 dol_syslog(get_class($this)."::update remove link with member. We will recreate it later", LOG_DEBUG);
2443 $sql = "UPDATE ".$this->db->prefix()."user SET fk_member = NULL where fk_member = ".((int) $this->fk_member);
2444 $resql = $this->db->query($sql);
2445 if (!$resql) {
2446 $this->error = $this->db->error();
2447 $this->db->rollback();
2448 return -5;
2449 }
2450 }
2451 // Set link to user
2452 dol_syslog(get_class($this)."::update set link with member", LOG_DEBUG);
2453 $sql = "UPDATE ".$this->db->prefix()."user SET fk_member =".($this->fk_member > 0 ? ((int) $this->fk_member) : 'null')." where rowid = ".((int) $this->id);
2454 $resql = $this->db->query($sql);
2455 if (!$resql) {
2456 $this->error = $this->db->error();
2457 $this->db->rollback();
2458 return -5;
2459 }
2460
2461 if ($nbrowsaffected) { // If something has changed in data
2462 if ($this->fk_member > 0 && !$nosyncmember) {
2463 dol_syslog(get_class($this)."::update user is linked with a member. We try to update member too.", LOG_DEBUG);
2464
2465 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
2466
2467 // This user is linked with a member, so we also update member information
2468 // if this is an update.
2469 $adh = new Adherent($this->db);
2470 $result = $adh->fetch($this->fk_member);
2471
2472 if ($result > 0) {
2473 $adh->civility_code = $this->civility_code;
2474 $adh->firstname = $this->firstname;
2475 $adh->lastname = $this->lastname;
2476 $adh->login = $this->login;
2477 $adh->gender = $this->gender;
2478 $adh->birth = $this->birth;
2479
2480 $adh->pass = $this->pass;
2481
2482 $adh->address = $this->address;
2483 $adh->town = $this->town;
2484 $adh->zip = $this->zip;
2485 $adh->state_id = $this->state_id;
2486 $adh->country_id = $this->country_id;
2487
2488 $adh->email = $this->email;
2489
2490 $adh->socialnetworks = $this->socialnetworks;
2491
2492 $adh->phone = $this->office_phone;
2493 $adh->phone_mobile = $this->user_mobile;
2494
2495 $adh->default_lang = $this->lang;
2496
2497 $adh->user_id = $this->id;
2498 $adh->user_login = $this->login;
2499
2500 $result = $adh->update($user, 0, 1, 0);
2501 if ($result < 0) {
2502 $this->error = $adh->error;
2503 $this->errors = $adh->errors;
2504 dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
2505 $error++;
2506 }
2507 } elseif ($result < 0) {
2508 $this->error = $adh->error;
2509 $this->errors = $adh->errors;
2510 $error++;
2511 }
2512 }
2513
2514 if ($this->contact_id > 0 && !$nosynccontact) {
2515 dol_syslog(get_class($this)."::update user is linked with a contact. We try to update contact too.", LOG_DEBUG);
2516
2517 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2518
2519 // This user is linked with a contact, so we also update contact information if this is an update.
2520 $tmpobj = new Contact($this->db);
2521 $result = $tmpobj->fetch($this->contact_id);
2522
2523 if ($result >= 0) {
2524 $tmpobj->civility_code = $this->civility_code;
2525 $tmpobj->firstname = $this->firstname;
2526 $tmpobj->lastname = $this->lastname;
2527 $tmpobj->login = $this->login;
2528 $tmpobj->gender = $this->gender;
2529 $tmpobj->birth = $this->birth;
2530
2531 //$tmpobj->pass=$this->pass;
2532
2533 $tmpobj->email = $this->email;
2534
2535 $tmpobj->socialnetworks = $this->socialnetworks;
2536
2537 $tmpobj->phone_pro = $this->office_phone;
2538 $tmpobj->phone_mobile = $this->user_mobile;
2539 $tmpobj->fax = $this->office_fax;
2540
2541 $tmpobj->default_lang = $this->lang;
2542
2543 $tmpobj->address = $this->address;
2544 $tmpobj->town = $this->town;
2545 $tmpobj->zip = $this->zip;
2546 $tmpobj->state_id = $this->state_id;
2547 $tmpobj->country_id = $this->country_id;
2548
2549 $tmpobj->user_id = $this->id;
2550 $tmpobj->user_login = $this->login;
2551
2552 $result = $tmpobj->update($tmpobj->id, $user, 0, 'update', 1);
2553 if ($result < 0) {
2554 $this->error = $tmpobj->error;
2555 $this->errors = $tmpobj->errors;
2556 dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
2557 $error++;
2558 }
2559 } else {
2560 $this->error = $tmpobj->error;
2561 $this->errors = $tmpobj->errors;
2562 $error++;
2563 }
2564 }
2565 }
2566
2567 $action = 'update';
2568
2569 // Actions on extra fields
2570 if (!$error) {
2571 $result = $this->insertExtraFields();
2572 if ($result < 0) {
2573 $error++;
2574 }
2575 }
2576
2577 if (!$error && !$notrigger) {
2578 // Call trigger
2579 $result = $this->call_trigger('USER_MODIFY', $user);
2580 if ($result < 0) {
2581 $error++;
2582 }
2583 // End call triggers
2584 }
2585
2586 if (!$error) {
2587 $this->db->commit();
2588 return $nbrowsaffected;
2589 } else {
2590 dol_syslog(get_class($this)."::update error=".$this->error, LOG_ERR);
2591 $this->db->rollback();
2592 return -1;
2593 }
2594 } else {
2595 $this->error = $this->db->lasterror();
2596 $this->db->rollback();
2597 return -2;
2598 }
2599 }
2600
2601 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2608 public function update_last_login_date()
2609 {
2610 // phpcs:enable
2611 $now = dol_now();
2612
2613 $userremoteip = getUserRemoteIP();
2614
2615 $sql = "UPDATE ".$this->db->prefix()."user SET";
2616 $sql .= " datepreviouslogin = datelastlogin,";
2617 $sql .= " ippreviouslogin = iplastlogin,";
2618 $sql .= " datelastlogin = '".$this->db->idate($now)."',";
2619 $sql .= " iplastlogin = '".$this->db->escape($userremoteip)."',";
2620 $sql .= " tms = tms"; // The last update date must change because the last login date is updated
2621 $sql .= " WHERE rowid = ".((int) $this->id);
2622
2623 dol_syslog(get_class($this)."::update_last_login_date user->id=".$this->id." ".$sql, LOG_DEBUG);
2624 $resql = $this->db->query($sql);
2625 if ($resql) {
2626 $this->datepreviouslogin = $this->datelastlogin;
2627 $this->datelastlogin = $now;
2628 $this->ippreviouslogin = $this->iplastlogin;
2629 $this->iplastlogin = $userremoteip;
2630 return 1;
2631 } else {
2632 $this->error = $this->db->lasterror().' sql='.$sql;
2633 return -1;
2634 }
2635 }
2636
2637
2650 public function setPassword($user, $password = '', $changelater = 0, $notrigger = 0, $nosyncmember = 0, $passwordalreadycrypted = 0, $flagdelsessionsbefore = 1)
2651 {
2652 global $conf, $langs;
2653 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2654
2655 $error = 0;
2656
2657 dol_syslog(get_class($this)."::setPassword user=".$user->id." password=".preg_replace('/./i', '*', $password)." changelater=".$changelater." notrigger=".$notrigger." nosyncmember=".$nosyncmember, LOG_DEBUG);
2658
2659 // If new password not provided, we generate one
2660 if (!$password) {
2661 $password = getRandomPassword(false);
2662 $passwordalreadycrypted = 0; // Just generated, so not crypted
2663 }
2664
2665 // Check and encrypt the password
2666 if (!empty($passwordalreadycrypted)) {
2667 $password_crypted = $password; // Reuse crypted password
2668 } else {
2669 if (getDolGlobalString('USER_PASSWORD_GENERATED')) {
2670 // Add a check on rules for password syntax using the setup of the password generator
2671 require_once DOL_DOCUMENT_ROOT.'/core/modules/security/generate/modules_genpassword.php';
2672 $modGeneratePass = ModeleGenPassword::loadAndInstantiate(getDolGlobalString('USER_PASSWORD_GENERATED'), $this->db, $conf, $langs, $user);
2673 if ($modGeneratePass) {
2674 '@phan-var-force ModeleGenPassword $modGeneratePass';
2675
2676 // To check an input user password, we disable the cleaning on ambiguous characters (this is used only for auto-generated password)
2677 $modGeneratePass->WithoutAmbi = 0;
2678
2679 // Call to validatePassword($password) to check pass match rules
2680 $testpassword = $modGeneratePass->validatePassword($password);
2681 if (!$testpassword) {
2682 $this->error = $modGeneratePass->error;
2683 return -1;
2684 }
2685 }
2686 }
2687
2688
2689 // Now, we encrypt the new password
2690 $password_crypted = (string) dol_hash($password);
2691 }
2692
2693 // Update password
2694 if (!$changelater) {
2695 if (!is_object($this->oldcopy)) {
2696 $this->oldcopy = clone $this;
2697 }
2698
2699 $now = dol_now();
2700
2701 $this->db->begin();
2702
2703 $sql = "UPDATE ".$this->db->prefix()."user";
2704 $sql .= " SET pass_crypted = '".$this->db->escape($password_crypted)."',";
2705 $sql .= " datelastpassvalidation = '".$this->db->idate(dol_now())."',";
2706 $sql .= " pass_temp = null,";
2707 $sql .= " force_pass_change = 0";
2708 if (!empty($flagdelsessionsbefore)) {
2709 $sql .= ", flagdelsessionsbefore = '".$this->db->idate($now - 5, 'gmt')."'";
2710 }
2711 if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
2712 $sql .= ", pass = null";
2713 } else {
2714 $sql .= ", pass = '".$this->db->escape($password)."'";
2715 }
2716 $sql .= " WHERE rowid = ".((int) $this->id);
2717
2718 dol_syslog(get_class($this)."::setPassword", LOG_DEBUG);
2719
2720 $result = $this->db->query($sql);
2721 if ($result) {
2722 if ($this->db->affected_rows($result)) {
2723 $this->pass = $password;
2724 $this->pass_indatabase = $password;
2725 $this->pass_indatabase_crypted = (string) $password_crypted;
2726 $this->force_pass_change = 0;
2727
2728 if ($this->fk_member && !$nosyncmember) {
2729 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
2730
2731 // This user is linked with a member, so we also update members information
2732 // if this is an update.
2733 $adh = new Adherent($this->db);
2734 $result = $adh->fetch($this->fk_member);
2735
2736 if ($result >= 0) {
2737 $result = $adh->setPassword($user, $this->pass, (!getDolGlobalString('DATABASE_PWD_ENCRYPTED') ? 0 : 1), 1); // The encryption is not managed in the 'adherent' module
2738 if (is_int($result) && $result < 0) {
2739 $this->error = $adh->error;
2740 dol_syslog(get_class($this)."::setPassword ".$this->error, LOG_ERR);
2741 $error++;
2742 }
2743 } else {
2744 $this->error = $adh->error;
2745 $error++;
2746 }
2747 }
2748
2749 dol_syslog(get_class($this)."::setPassword notrigger=".$notrigger." error=".$error, LOG_DEBUG);
2750
2751 // Call trigger for the "security events" log
2752 $user->context['audit'] = 'login='.$user->login;
2753 if (!empty($flagdelsessionsbefore)) {
2754 $user->context['audit'] .= " - flagdelsessionsbefore set to '".$this->db->idate($now - 5, 'gmt')."'";
2755 }
2756
2757 if (!$error && !$notrigger) {
2758 // Call trigger
2759 $result = $this->call_trigger('USER_NEW_PASSWORD', $user);
2760 if ($result < 0) {
2761 $error++;
2762 $this->db->rollback();
2763 return -1;
2764 }
2765 // End call triggers
2766 }
2767
2768 $this->db->commit();
2769 return $this->pass;
2770 } else {
2771 $this->db->rollback();
2772 return 0;
2773 }
2774 } else {
2775 $this->db->rollback();
2776 dol_print_error($this->db);
2777 return -1;
2778 }
2779 } else {
2780 // We store password in password temporary field.
2781 // After receiving confirmation link, we will erase and store it in pass_crypted
2782 $sql = "UPDATE ".$this->db->prefix()."user";
2783 $sql .= " SET pass_temp = '".$this->db->escape($password)."'";
2784 $sql .= " WHERE rowid = ".((int) $this->id);
2785
2786 dol_syslog(get_class($this)."::setPassword", LOG_DEBUG); // No log
2787 $result = $this->db->query($sql);
2788 if ($result) {
2789 return $password;
2790 } else {
2791 dol_print_error($this->db);
2792 return -3;
2793 }
2794 }
2795 }
2796
2797 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2806 public function send_password($user, $password = '', $changelater = 0)
2807 {
2808 // phpcs:enable
2809 global $conf, $langs;
2811
2812 require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2813
2814 $msgishtml = 0;
2815
2816 // Define $msg
2817 $mesg = '';
2818
2819 $outputlangs = new Translate("", $conf);
2820
2821 if (getDolGlobalString('MAIN_LANG_DEFAULT')) {
2822 $outputlangs->setDefaultLang(getDolGlobalString('MAIN_LANG_DEFAULT'));
2823 } else { // If user has not defined its own language, we used current language
2824 $outputlangs = $langs;
2825 }
2826
2827 // Load translation files required by the page
2828 $outputlangs->loadLangs(array("main", "errors", "users", "other"));
2829
2830 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', constant('DOL_APPLICATION_TITLE'));
2831
2832 $subject = '['.$appli.'] '.$outputlangs->transnoentitiesnoconv("SubjectNewPassword", $appli);
2833
2834 // Define $urlwithroot
2835 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2836 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
2837
2838 if (!$changelater) {
2839 $url = $urlwithroot.'/';
2840 if (getDolGlobalString('URL_REDIRECTION_AFTER_CHANGEPASSWORD')) {
2841 $url = getDolGlobalString('URL_REDIRECTION_AFTER_CHANGEPASSWORD');
2842 }
2843
2844 dol_syslog(get_class($this)."::send_password changelater is off, url=".$url);
2845
2846 $mesg .= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived")."\n";
2847 $mesg .= $outputlangs->transnoentitiesnoconv("NewKeyIs")." :\n\n";
2848 $mesg .= $outputlangs->transnoentitiesnoconv("Login")." = ".$this->login."\n";
2849 $mesg .= $outputlangs->transnoentitiesnoconv("Password")." = ".$password."\n\n";
2850 $mesg .= "\n";
2851
2852 $mesg .= $outputlangs->transnoentitiesnoconv("ClickHereToGoTo", $appli).': '.$url."\n\n";
2853 $mesg .= "--\n";
2854 $mesg .= $user->getFullName($outputlangs); // Username that send the email (not the user for who we want to reset password)
2855 } else {
2856 //print $password.'-'.$this->id.'-'.$conf->file->instance_unique_id;
2857 $url = $urlwithroot.'/user/passwordforgotten.php?action=validatenewpassword';
2858 $url .= '&username='.urlencode($this->login)."&passworduidhash=".urlencode(dol_hash($password.'-'.$this->id.'-'.$conf->file->instance_unique_id));
2859 if (isModEnabled('multicompany')) {
2860 $url .= '&entity='.(!empty($this->entity) ? $this->entity : 1);
2861 }
2862
2863 dol_syslog(get_class($this)."::send_password changelater is on, url=".$url);
2864
2865 $msgishtml = 1;
2866
2867 $mesg .= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived")."<br>\n";
2868 $mesg .= $outputlangs->transnoentitiesnoconv("NewKeyWillBe")." :<br>\n<br>\n";
2869 $mesg .= '<strong>'.$outputlangs->transnoentitiesnoconv("Login")."</strong> = ".$this->login."<br>\n";
2870 $mesg .= '<strong>'.$outputlangs->transnoentitiesnoconv("Password")."</strong> = ".$password."<br>\n<br>\n";
2871 $mesg .= "<br>\n";
2872 $mesg .= $outputlangs->transnoentitiesnoconv("YouMustClickToChange")." :<br>\n";
2873 $mesg .= '<a href="'.$url.'" rel="noopener">'.$outputlangs->transnoentitiesnoconv("ConfirmPasswordChange").'</a>'."<br>\n<br>\n";
2874 $mesg .= $outputlangs->transnoentitiesnoconv("ForgetIfNothing")."<br>\n<br>\n";
2875 }
2876
2877 $trackid = 'use'.$this->id;
2878 $sendcontext = 'passwordreset';
2879
2880 $mailfile = new CMailFile(
2881 $subject,
2882 $this->email,
2883 getDolGlobalString("MAIN_MAIL_EMAIL_FROM_PASSWORDRESET", getDolGlobalString("MAIN_MAIL_EMAIL_FROM")),
2884 $mesg,
2885 array(),
2886 array(),
2887 array(),
2888 '',
2889 '',
2890 0,
2891 $msgishtml,
2892 '',
2893 '',
2894 $trackid,
2895 '',
2896 $sendcontext
2897 );
2898
2899 if ($mailfile->sendfile()) {
2900 return 1;
2901 } else {
2902 $langs->trans("errors");
2903 $this->error = $langs->trans("ErrorFailedToSendPassword").' '.$mailfile->error;
2904 return -1;
2905 }
2906 }
2907
2913 public function error()
2914 {
2915 return $this->error;
2916 }
2917
2918
2919 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2925 public function fetch_clicktodial()
2926 {
2927 // phpcs:enable
2928 $sql = "SELECT url, login, pass, poste ";
2929 $sql .= " FROM ".$this->db->prefix()."user_clicktodial as u";
2930 $sql .= " WHERE u.fk_user = ".((int) $this->id);
2931
2932 $resql = $this->db->query($sql);
2933 if ($resql) {
2934 if ($this->db->num_rows($resql)) {
2935 $obj = $this->db->fetch_object($resql);
2936
2937 $this->clicktodial_url = $obj->url;
2938 $this->clicktodial_login = $obj->login;
2939 $this->clicktodial_password = $obj->pass;
2940 $this->clicktodial_poste = $obj->poste;
2941 }
2942
2943 $this->clicktodial_loaded = 1; // Data loaded (found or not)
2944
2945 $this->db->free($resql);
2946 return 1;
2947 } else {
2948 $this->error = $this->db->error();
2949 return -1;
2950 }
2951 }
2952
2953 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2959 public function update_clicktodial()
2960 {
2961 // phpcs:enable
2962 $this->db->begin();
2963
2964 $sql = "DELETE FROM ".$this->db->prefix()."user_clicktodial";
2965 $sql .= " WHERE fk_user = ".((int) $this->id);
2966
2967 dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2968
2969 $result = $this->db->query($sql);
2970
2971 $sql = "INSERT INTO ".$this->db->prefix()."user_clicktodial";
2972 $sql .= " (fk_user,url,login,pass,poste)";
2973 $sql .= " VALUES (".((int) $this->id);
2974 $sql .= ", '".$this->db->escape($this->clicktodial_url)."'";
2975 $sql .= ", '".$this->db->escape($this->clicktodial_login)."'";
2976 $sql .= ", '".$this->db->escape($this->clicktodial_password)."'";
2977 $sql .= ", '".$this->db->escape($this->clicktodial_poste)."')";
2978
2979 dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2980
2981 $result = $this->db->query($sql);
2982 if ($result) {
2983 $this->db->commit();
2984 return 1;
2985 } else {
2986 $this->db->rollback();
2987 $this->error = $this->db->lasterror();
2988 return -1;
2989 }
2990 }
2991
2992
2993 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3002 public function SetInGroup($group, $entity, $notrigger = 0)
3003 {
3004 // phpcs:enable
3005 global $langs, $user;
3006
3007 $error = 0;
3008
3009 $this->db->begin();
3010
3011 $sql = "DELETE FROM ".$this->db->prefix()."usergroup_user";
3012 $sql .= " WHERE fk_user = ".((int) $this->id);
3013 $sql .= " AND fk_usergroup = ".((int) $group);
3014 $sql .= " AND entity = ".((int) $entity);
3015
3016 $result = $this->db->query($sql);
3017
3018 $sql = "INSERT INTO ".$this->db->prefix()."usergroup_user (entity, fk_user, fk_usergroup)";
3019 $sql .= " VALUES (".((int) $entity).",".((int) $this->id).",".((int) $group).")";
3020
3021 $result = $this->db->query($sql);
3022 if ($result) {
3023 if (!$error && !$notrigger) {
3024 $this->context = array('audit' => $langs->trans("UserSetInGroup"), 'newgroupid' => $group);
3025
3026 // Call trigger
3027 $result = $this->call_trigger('USER_MODIFY', $user);
3028 if ($result < 0) {
3029 $error++;
3030 }
3031 // End call triggers
3032 }
3033
3034 if (!$error) {
3035 $this->db->commit();
3036 return 1;
3037 } else {
3038 dol_syslog(get_class($this)."::SetInGroup ".$this->error, LOG_ERR);
3039 $this->db->rollback();
3040 return -2;
3041 }
3042 } else {
3043 $this->error = $this->db->lasterror();
3044 $this->db->rollback();
3045 return -1;
3046 }
3047 }
3048
3049 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3058 public function RemoveFromGroup($group, $entity, $notrigger = 0)
3059 {
3060 // phpcs:enable
3061 global $langs, $user;
3062
3063 $error = 0;
3064
3065 $this->db->begin();
3066
3067 $sql = "DELETE FROM ".$this->db->prefix()."usergroup_user";
3068 $sql .= " WHERE fk_user = ".((int) $this->id);
3069 $sql .= " AND fk_usergroup = ".((int) $group);
3070 if (empty($entity)) {
3071 $sql .= " AND entity IN (0, 1)"; // group may be in entity 0 (so $entity=0) and link with user into entity 1.
3072 } else {
3073 $sql .= " AND entity = ".((int) $entity);
3074 }
3075
3076 $result = $this->db->query($sql);
3077 if ($result) {
3078 if (!$error && !$notrigger) {
3079 $this->context = array('audit' => $langs->trans("UserRemovedFromGroup"), 'oldgroupid' => $group);
3080
3081 // Call trigger
3082 $result = $this->call_trigger('USER_MODIFY', $user);
3083 if ($result < 0) {
3084 $error++;
3085 }
3086 // End call triggers
3087 }
3088
3089 if (!$error) {
3090 $this->db->commit();
3091 return 1;
3092 } else {
3093 dol_syslog(get_class($this)."::RemoveFromGroup ".$this->error, LOG_ERR);
3094 $this->db->rollback();
3095 return -2;
3096 }
3097 } else {
3098 $this->error = $this->db->lasterror();
3099 $this->db->rollback();
3100 return -1;
3101 }
3102 }
3103
3104
3112 {
3113 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3114
3115 $now = dol_now();
3116
3117 //dol_syslog("isNotIntoValidityDateRange ".$this->datestartvalidity);
3118
3119 // Check date start validity
3120 if ($this->datestartvalidity && $this->datestartvalidity > dol_get_last_hour($now)) {
3121 return 1;
3122 }
3123 // Check date end validity
3124 if ($this->dateendvalidity && $this->dateendvalidity < dol_get_first_hour($now)) {
3125 return 1;
3126 }
3127
3128 return 0;
3129 }
3130
3131
3143 public function getPhotoUrl($width, $height, $cssclass = '', $imagesize = '')
3144 {
3145 $result = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
3146 $result .= Form::showphoto('userphoto', $this, $width, $height, 0, $cssclass, $imagesize);
3147 $result .= '</a>';
3148
3149 return $result;
3150 }
3151
3158 public function getTooltipContentArray($params)
3159 {
3160 global $conf, $langs, $menumanager;
3161 global $dolibarr_main_demo;
3162
3163 $infologin = $params['infologin'] ?? 0;
3164 $option = $params['option'] ?? '';
3165
3166 $data = [];
3167 if (!empty($this->photo)) {
3168 $photo = '<div class="photointooltip floatright">';
3169 $photo .= Form::showphoto('userphoto', $this, 0, 60, 0, 'photoref photowithmargin photologintooltip', 'small', 0, 1); // Force height to 60 so we total height of tooltip can be calculated and collision can be managed
3170 $photo .= '</div>';
3171 $data['photo'] = $photo;
3172 //$label .= '<div style="clear: both;"></div>';
3173 }
3174
3175 // Info Login
3176 $data['opendiv'] = '<div class="centpercent divtooltip">';
3177 $data['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("User").'</u> '.$this->getLibStatut(4);
3178 $data['name'] = '<br><b>'.$langs->trans('Name').':</b> '.dol_string_nohtmltag($this->getFullName($langs));
3179 if (!empty($this->login)) {
3180 $data['login'] = '<br><b>'.$langs->trans('Login').':</b> '.dol_string_nohtmltag($this->login);
3181 }
3182 if (!empty($this->job)) {
3183 $data['job'] = '<br><b>'.$langs->trans("Job").':</b> '.dol_string_nohtmltag($this->job);
3184 }
3185 $data['email'] = '<br><b>'.$langs->trans("Email").':</b> '.dol_string_nohtmltag($this->email);
3186 if (!empty($this->office_phone) || !empty($this->office_fax) || !empty($this->fax)) {
3187 $phonelist = array();
3188 if ($this->office_phone) {
3189 $phonelist[] = dol_print_phone($this->office_phone, $this->country_code, $this->id, 0, '', '&nbsp', 'phone');
3190 }
3191 if ($this->office_fax) {
3192 $phonelist[] = dol_print_phone($this->office_fax, $this->country_code, $this->id, 0, '', '&nbsp', 'fax');
3193 }
3194 if ($this->user_mobile) {
3195 $phonelist[] = dol_print_phone($this->user_mobile, $this->country_code, $this->id, 0, '', '&nbsp', 'mobile');
3196 }
3197 $data['phones'] = '<br><b>'.$langs->trans('Phone').':</b> '.implode('&nbsp;', $phonelist);
3198 }
3199 if (!empty($this->admin)) {
3200 $data['administrator'] = '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($this->admin);
3201 }
3202 if (!empty($this->accountancy_code) || $option == 'accountancy') {
3203 $langs->load("companies");
3204 $data['accountancycode'] = '<br><b>'.$langs->trans("AccountancyCode").'</b>: '.$this->accountancy_code;
3205 }
3206 $company = '';
3207 if (!empty($this->socid)) { // Add thirdparty for external users
3208 $thirdpartystatic = new Societe($this->db);
3209 $thirdpartystatic->fetch($this->socid);
3210 $companyimg = '';
3211 if (empty($params['hidethirdpartylogo'])) {
3212 $companyimg = ' '.$thirdpartystatic->getNomUrl(2, 'nolink', 0, 1); // picto only of company
3213 }
3214 $company = ' ('.$langs->trans("Company").': '.($companyimg ? $companyimg : img_picto('', 'company')).' '.dol_string_nohtmltag($thirdpartystatic->name).')';
3215 }
3216 $type = ($this->socid ? $langs->trans("ExternalUser").$company : $langs->trans("InternalUser"));
3217 $data['type'] = '<br><b>'.$langs->trans("Type").':</b> '.$type;
3218 $data['closediv'] = '</div>';
3219
3220 if ($infologin > 0) {
3221 $data['newlinelogin'] = '<br>';
3222 $data['session'] = '<br><u>'.$langs->trans("Session").'</u>';
3223 $data['ip'] = '<br><b>'.$langs->trans("IPAddress").'</b>: '.dol_string_nohtmltag(getUserRemoteIP());
3224 if (getDolGlobalString('MAIN_MODULE_MULTICOMPANY')) {
3225 $data['multicompany'] = '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (User entity '.$this->entity.')';
3226 }
3227 $data['authentication'] = '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.dol_string_nohtmltag($_SESSION["dol_authmode"].(empty($dolibarr_main_demo) ? '' : ' (demo)'));
3228 $data['connectedsince'] = '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($this->datelastlogin, "dayhour", 'tzuser');
3229 $data['previousconnexion'] = '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($this->datepreviouslogin, "dayhour", 'tzuser');
3230 $data['currenttheme'] = '<br><b>'.$langs->trans("CurrentTheme").':</b> '.dol_string_nohtmltag($conf->theme);
3231 // @phan-suppress-next-line PhanRedefinedClassReference
3232 $data['currentmenumanager'] = '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.dol_string_nohtmltag($menumanager->name);
3233 $s = picto_from_langcode($langs->getDefaultLang());
3234 $data['currentuserlang'] = '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.dol_string_nohtmltag(($s ? $s.' ' : '').$langs->getDefaultLang());
3235 $data['browser'] = '<br><b>'.$langs->trans("Browser").':</b> '.dol_string_nohtmltag($conf->browser->name.($conf->browser->version ? ' '.$conf->browser->version : '').' ('.($_SERVER['HTTP_USER_AGENT'] ?? '').')');
3236 $data['layout'] = '<br><b>'.$langs->trans("Layout").':</b> '.dol_string_nohtmltag($conf->browser->layout);
3237 $data['screen'] = '<br><b>'.$langs->trans("Screen").':</b> '.dol_string_nohtmltag($_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight']);
3238 if ($conf->browser->layout == 'phone') {
3239 $data['phone'] = '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
3240 }
3241 if (!empty($_SESSION["disablemodules"])) {
3242 $data['disabledmodules'] = '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.dol_string_nohtmltag(implode(', ', explode(',', $_SESSION["disablemodules"])));
3243 }
3244 }
3245
3246 return $data;
3247 }
3248
3264 public function getNomUrl($withpictoimg = 0, $option = '', $infologin = 0, $notooltip = 0, $maxlen = 24, $hidethirdpartylogo = 0, $mode = '', $morecss = '', $save_lastsearch_value = -1)
3265 {
3266 global $langs, $hookmanager, $user;
3267
3268 if (!$user->hasRight('user', 'user', 'read') && $user->id != $this->id) {
3269 $option = 'nolink';
3270 }
3271
3272 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpictoimg) {
3273 $withpictoimg = 0;
3274 }
3275
3276 $result = '';
3277 $params = [
3278 'id' => $this->id,
3279 'objecttype' => $this->element,
3280 'infologin' => $infologin,
3281 'option' => $option,
3282 'hidethirdpartylogo' => $hidethirdpartylogo,
3283 ];
3284 $classfortooltip = 'classfortooltip';
3285 $dataparams = '';
3286 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
3287 $classfortooltip = 'classforajaxtooltip';
3288 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
3289 $label = '';
3290 } else {
3291 $label = implode($this->getTooltipContentArray($params));
3292 }
3293
3294 $companylink = '';
3295 if (!empty($this->socid)) { // Add thirdparty for external users
3296 $thirdpartystatic = new Societe($this->db);
3297 $thirdpartystatic->fetch($this->socid);
3298 if (empty($hidethirdpartylogo)) {
3299 $companylink = ' '.$thirdpartystatic->getNomUrl(2, 'nolink', 0, 1); // picto only of company
3300 }
3301 }
3302
3303 if ($infologin < 0) {
3304 $label = '';
3305 }
3306
3307 $baseurl = DOL_URL_ROOT . '/user/card.php';
3308 if ($option == 'leave') {
3309 $baseurl = DOL_URL_ROOT . '/holiday/list.php';
3310 }
3311 $query = ['id' => $this->id];
3312 if ($option != 'nolink') {
3313 // Add param to save lastsearch_values or not
3314 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
3315 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
3316 $add_save_lastsearch_values = 1;
3317 }
3318 if ($add_save_lastsearch_values) {
3319 $query = array_merge($query, ['save_lastsearch_values' => 1]);
3320 }
3321 }
3322 $url = dolBuildUrl($baseurl, $query);
3323
3324 $linkstart = '<a href="'.$url.'"';
3325 $linkclose = "";
3326 if (empty($notooltip)) {
3327 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3328 $langs->load("users");
3329 $label = $langs->trans("ShowUser");
3330 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
3331 }
3332 $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
3333 $linkclose .= $dataparams . ' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
3334 } else {
3335 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
3336 }
3337
3338 $linkstart .= $linkclose.'>';
3339 $linkend = '</a>';
3340
3341 //if ($withpictoimg == -1) $result.='<div class="nowrap">';
3342 $result .= (($option == 'nolink') ? '' : $linkstart);
3343 if ($withpictoimg) {
3344 $paddafterimage = '';
3345 if (abs((int) $withpictoimg) == 1 || abs((int) $withpictoimg) == 4) {
3346 $paddafterimage = 'style="margin-'.($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right').': 3px;"';
3347 }
3348 // Only picto
3349 if ($withpictoimg > 0) {
3350 $picto = '<!-- picto user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'"><div class="valignmiddle userphoto inline-block center marginrightonlyshort"'.($paddafterimage ? ' '.$paddafterimage : '').'>'.img_object('', 'user', 'class=""', 0, 0, $notooltip ? 0 : 1).'</div></span>';
3351 } else {
3352 // Picto must be a photo
3353 $picto = '<!-- picto photo user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'"'.($paddafterimage ? ' '.$paddafterimage : '').'>';
3354 $picto .= Form::showphoto('userphoto', $this, 0, 0, 0, 'userphoto'.(($withpictoimg == -3 || $withpictoimg == -4) ? 'small' : ''), 'mini', 0, 1);
3355 $picto .= '</span>';
3356 }
3357 $result .= $picto;
3358 }
3359
3360 if ($withpictoimg == -4 || ($withpictoimg > -2 && $withpictoimg != 2)) {
3361 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3362 $result .= '<span class="nopadding usertext'.((!isset($this->status) || $this->status) ? '' : ' strikefordisabled').($morecss ? ' '.$morecss : '').'">';
3363 }
3364 if ($mode == 'login') {
3365 $result .= dol_string_nohtmltag(dol_trunc($this->login, $maxlen));
3366 } else {
3367 $result .= dol_string_nohtmltag($this->getFullName($langs, 0, ($mode == 'firstelselast' ? 3 : ($mode == 'firstname' ? 2 : -1)), $maxlen));
3368 }
3369 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3370 $result .= '</span>';
3371 }
3372 }
3373 $result .= (($option == 'nolink') ? '' : $linkend);
3374 //if ($withpictoimg == -1) $result.='</div>';
3375
3376 $result .= $companylink;
3377
3378 global $action;
3379 $hookmanager->initHooks(array('userdao'));
3380 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
3381 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3382 if ($reshook > 0) {
3383 $result = $hookmanager->resPrint;
3384 } else {
3385 $result .= $hookmanager->resPrint;
3386 }
3387
3388 return $result;
3389 }
3390
3400 public function getLoginUrl($withpictoimg = 0, $option = '', $notooltip = 0, $morecss = '')
3401 {
3402 global $langs, $user;
3403
3404 $result = '';
3405
3406 $linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
3407 $linkend = '</a>';
3408
3409 //Check user's rights to see an other user
3410 if ((!$user->hasRight('user', 'user', 'lire') && $this->id != $user->id)) {
3411 $option = 'nolink';
3412 }
3413
3414 if ($option == 'xxx') {
3415 $linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
3416 $linkend = '</a>';
3417 }
3418
3419 if ($option == 'nolink') {
3420 $linkstart = '';
3421 $linkend = '';
3422 }
3423
3424 $result .= $linkstart;
3425 if ($withpictoimg) {
3426 $paddafterimage = '';
3427 if (abs($withpictoimg) == 1) {
3428 $paddafterimage = 'style="margin-'.($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right').': 3px;"';
3429 }
3430 // Only picto
3431 if ($withpictoimg > 0) {
3432 $picto = '<!-- picto user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'">'.img_object('', 'user', $paddafterimage.' '.($notooltip ? '' : 'class="paddingright classfortooltip"'), 0, 0, $notooltip ? 0 : 1).'</span>';
3433 } else {
3434 // Picto must be a photo
3435 $picto = '<!-- picto photo user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'"'.($paddafterimage ? ' '.$paddafterimage : '').'>'.Form::showphoto('userphoto', $this, 0, 0, 0, 'userphoto'.($withpictoimg == -3 ? 'small' : ''), 'mini', 0, 1).'</span>';
3436 }
3437 $result .= $picto;
3438 }
3439 $result .= $this->login;
3440 $result .= $linkend;
3441
3442 return $result;
3443 }
3444
3451 public function getLibStatut($mode = 0)
3452 {
3453 return $this->LibStatut(isset($this->status) ? (int) $this->status : (int) $this->statut, $mode); // $this->statut is deprecated
3454 }
3455
3456 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3464 public function LibStatut($status, $mode = 0)
3465 {
3466 // phpcs:enable
3467 global $langs;
3468
3469 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
3470 global $langs;
3471 //$langs->load("mymodule");
3472 $this->labelStatus[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
3473 $this->labelStatus[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
3474 $this->labelStatusShort[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
3475 $this->labelStatusShort[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
3476 }
3477
3478 $statusType = 'status5';
3479 if ($status == self::STATUS_ENABLED) {
3480 $statusType = 'status4';
3481 }
3482
3483 $label = $this->labelStatus[$status];
3484 $labelshort = $this->labelStatusShort[$status];
3485
3486 $now = dol_now();
3487 if (!empty($this->datestartvalidity) && $now < $this->datestartvalidity) {
3488 $statusType = 'status3';
3489 $label .= ' ('.$langs->trans("UserNotYetValid").')';
3490 }
3491 if (!empty($this->dateendvalidity) && $now > ($this->dateendvalidity + 24 * 3600 - 1)) {
3492 $statusType = 'status2';
3493 $label .= ' ('.$langs->trans("UserExpired").')';
3494 }
3495
3496 return dolGetStatus($label, $labelshort, '', $statusType, $mode);
3497 }
3498
3499
3507 public function getKanbanView($option = '', $arraydata = null)
3508 {
3509 global $langs;
3510
3511 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3512
3513 $return = '<div class="box-flex-item box-flex-grow-zero">';
3514 $return .= '<div class="info-box info-box-sm">';
3515 $return .= '<span class="info-box-icon bg-infobox-action">';
3516
3517 $label = '';
3518 if (!empty($this->photo)) {
3519 //$label .= '<div class="photointooltip floatright">';
3520 $label .= Form::showphoto('userphoto', $this, 0, 60, 0, 'photokanban photoref photowithmargin photologintooltip', 'small', 0, 1); // Force height to 60 so we total height of tooltip can be calculated and collision can be managed
3521 //$label .= '</div>';
3522 //$label .= '<div style="clear: both;"></div>';
3523 $return .= $label;
3524 } else {
3525 $return .= img_picto('', $this->picto);
3526 }
3527
3528 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
3529 $return .= '</span>';
3530 $return .= '<div class="info-box-content">';
3531 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(0, '', 0, 0, 24, 0, '', 'valignmiddle') : $this->ref);
3532 if (isModEnabled('multicompany') && $this->admin && !$this->entity) {
3533 $return .= img_picto($langs->trans("SuperAdministratorDesc"), 'superadmin', 'class="valignmiddle paddingright paddingleft"');
3534 } elseif ($this->admin) {
3535 $return .= img_picto($langs->trans("AdministratorDesc"), 'admin', 'class="valignmiddle paddingright paddingleft"');
3536 }
3537 $return .= '</span>';
3538 if ($selected >= 0) {
3539 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3540 }
3541 if (property_exists($this, 'label')) {
3542 $return .= '<br><span class="info-box-label opacitymedium">'.$this->label.'</span>';
3543 }
3544 if ($this->email) {
3545 $return .= '<br><span class="info-box-label opacitymedium small">'.img_picto('', 'email').' '.$this->email.'</span>';
3546 }
3547 if (method_exists($this, 'getLibStatut')) {
3548 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
3549 }
3550 $return .= '</div>';
3551 $return .= '</div>';
3552 $return .= '</div>';
3553
3554 return $return;
3555 }
3556
3557
3558 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
3559 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3569 public function _load_ldap_dn($info, $mode = 0)
3570 {
3571 // phpcs:enable
3572 global $conf;
3573 $dn = '';
3574 if ($mode == 0) {
3575 $dn = getDolGlobalString('LDAP_KEY_USERS') . "=".$info[getDolGlobalString('LDAP_KEY_USERS')]."," . getDolGlobalString('LDAP_USER_DN');
3576 } elseif ($mode == 1) {
3577 $dn = getDolGlobalString('LDAP_USER_DN');
3578 } elseif ($mode == 2) {
3579 $dn = getDolGlobalString('LDAP_KEY_USERS') . "=".$info[getDolGlobalString('LDAP_KEY_USERS')];
3580 }
3581 return $dn;
3582 }
3583
3584 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
3585 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3591 public function _load_ldap_info()
3592 {
3593 // phpcs:enable
3594 global $conf, $langs;
3595
3596 $info = array();
3597
3598 $socialnetworks = getArrayOfSocialNetworks();
3599
3600 $keymodified = false;
3601
3602 // Object classes
3603 $info["objectclass"] = explode(',', getDolGlobalString('LDAP_USER_OBJECT_CLASS'));
3604
3605 $this->fullname = $this->getFullName($langs);
3606
3607 // Possible LDAP KEY (constname => varname)
3608 $ldapkey = array(
3609 'LDAP_FIELD_FULLNAME' => 'fullname',
3610 'LDAP_FIELD_NAME' => 'lastname',
3611 'LDAP_FIELD_FIRSTNAME' => 'firstname',
3612 'LDAP_FIELD_LOGIN' => 'login',
3613 'LDAP_FIELD_LOGIN_SAMBA' => 'login',
3614 'LDAP_FIELD_PHONE' => 'office_phone',
3615 'LDAP_FIELD_MOBILE' => 'user_mobile',
3616 'LDAP_FIELD_FAX' => 'office_fax',
3617 'LDAP_FIELD_MAIL' => 'email',
3618 'LDAP_FIELD_SID' => 'ldap_sid',
3619 );
3620
3621 // Champs
3622 foreach ($ldapkey as $constname => $varname) {
3623 if (!empty($this->$varname) && getDolGlobalString($constname)) {
3624 $info[getDolGlobalString($constname)] = $this->$varname;
3625
3626 // Check if it is the LDAP key and if its value has been changed
3627 if (getDolGlobalString('LDAP_KEY_USERS') && getDolGlobalString('LDAP_KEY_USERS') == getDolGlobalString($constname)) {
3628 if (is_object($this->oldcopy) && !empty($this->oldcopy->id) && $this->$varname != $this->oldcopy->$varname) {
3629 $keymodified = true; // For check if LDAP key has been modified
3630 }
3631 }
3632 }
3633 }
3634 foreach ($socialnetworks as $key => $value) {
3635 if (!empty($this->socialnetworks[$value['label']]) && getDolGlobalString('LDAP_FIELD_'.strtoupper($value['label']))) {
3636 $info[getDolGlobalString('LDAP_FIELD_'.strtoupper($value['label']))] = $this->socialnetworks[$value['label']];
3637 }
3638 }
3639 if ($this->address && getDolGlobalString('LDAP_FIELD_ADDRESS')) {
3640 $info[getDolGlobalString('LDAP_FIELD_ADDRESS')] = $this->address;
3641 }
3642 if ($this->zip && getDolGlobalString('LDAP_FIELD_ZIP')) {
3643 $info[getDolGlobalString('LDAP_FIELD_ZIP')] = $this->zip;
3644 }
3645 if ($this->town && getDolGlobalString('LDAP_FIELD_TOWN')) {
3646 $info[getDolGlobalString('LDAP_FIELD_TOWN')] = $this->town;
3647 }
3648 if ($this->note_public && getDolGlobalString('LDAP_FIELD_DESCRIPTION')) {
3649 $info[getDolGlobalString('LDAP_FIELD_DESCRIPTION')] = dol_string_nohtmltag($this->note_public, 2);
3650 }
3651 if ($this->socid > 0 && getDolGlobalString('LDAP_FIELD_COMPANY')) {
3652 $soc = new Societe($this->db);
3653 $soc->fetch($this->socid);
3654
3655 $info[getDolGlobalString('LDAP_FIELD_COMPANY')] = $soc->name;
3656 if ($soc->client == 1) {
3657 $info["businessCategory"] = "Customers";
3658 }
3659 if ($soc->client == 2) {
3660 $info["businessCategory"] = "Prospects";
3661 }
3662 if ($soc->fournisseur == 1) {
3663 $info["businessCategory"] = "Suppliers";
3664 }
3665 }
3666
3667 // When password is modified
3668 if (!empty($this->pass)) {
3669 if (getDolGlobalString('LDAP_FIELD_PASSWORD')) {
3670 $info[getDolGlobalString('LDAP_FIELD_PASSWORD')] = $this->pass; // this->pass = unencrypted password
3671 }
3672 if (getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')) {
3673 $info[getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')] = dol_hash($this->pass, 'openldap'); // Create OpenLDAP password (see LDAP_PASSWORD_HASH_TYPE)
3674 }
3675 } elseif (getDolGlobalString('LDAP_SERVER_PROTOCOLVERSION') !== '3') {
3676 // Set LDAP password if possible
3677 // If ldap key is modified and LDAPv3 we use ldap_rename function for avoid lose encrypt password
3678 if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
3679 // Just for the default MD5 !
3680 if (!getDolGlobalString('MAIN_SECURITY_HASH_ALGO')) {
3681 if ($this->pass_indatabase_crypted && getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')) {
3682 $info[getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')] = dolGetLdapPasswordHash($this->pass_indatabase_crypted, 'md5frommd5'); // Create OpenLDAP MD5 password from Dolibarr MD5 password
3683 }
3684 }
3685 } elseif (!empty($this->pass_indatabase)) {
3686 // Use $this->pass_indatabase value if exists
3687 if (getDolGlobalString('LDAP_FIELD_PASSWORD')) {
3688 $info[getDolGlobalString('LDAP_FIELD_PASSWORD')] = $this->pass_indatabase; // $this->pass_indatabase = unencrypted password
3689 }
3690 if (getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')) {
3691 $info[getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')] = dol_hash($this->pass_indatabase, 'openldap'); // Create OpenLDAP password (see LDAP_PASSWORD_HASH_TYPE)
3692 }
3693 }
3694 }
3695
3696 if (getDolGlobalString('LDAP_SERVER_TYPE') == 'egroupware') {
3697 $info["objectclass"][4] = "phpgwContact"; // compatibilite egroupware
3698
3699 $info['uidnumber'] = $this->id;
3700
3701 $info['phpgwTz'] = 0;
3702 $info['phpgwMailType'] = 'INTERNET';
3703 $info['phpgwMailHomeType'] = 'INTERNET';
3704
3705 $info["phpgwContactTypeId"] = 'n';
3706 $info["phpgwContactCatId"] = 0;
3707 $info["phpgwContactAccess"] = "public";
3708
3709 $info["phpgwContactOwner"] = 1;
3710
3711 if ($this->email) {
3712 $info["rfc822Mailbox"] = $this->email;
3713 }
3714 if ($this->user_mobile) {
3715 $info["phpgwCellTelephoneNumber"] = $this->user_mobile;
3716 }
3717 }
3718
3719 if (getDolGlobalString('LDAP_FIELD_USERID')) {
3720 $info[getDolGlobalString('LDAP_FIELD_USERID')] = $this->id;
3721 }
3722 if (getDolGlobalString('LDAP_FIELD_GROUPID')) {
3723 $usergroup = new UserGroup($this->db);
3724 $groupslist = $usergroup->listGroupsForUser($this->id);
3725 $info[getDolGlobalString('LDAP_FIELD_GROUPID')] = '65534';
3726 if (!empty($groupslist)) {
3727 foreach ($groupslist as $groupforuser) {
3728 $info[getDolGlobalString('LDAP_FIELD_GROUPID')] = $groupforuser->id; //Select first group in list
3729 break;
3730 }
3731 }
3732 }
3733 if (getDolGlobalString('LDAP_FIELD_HOMEDIRECTORY') && getDolGlobalString('LDAP_FIELD_HOMEDIRECTORYPREFIX')) {
3734 $info[getDolGlobalString('LDAP_FIELD_HOMEDIRECTORY')] = getDolGlobalString('LDAP_FIELD_HOMEDIRECTORYPREFIX')."/".$this->login;
3735 }
3736
3737 return $info;
3738 }
3739
3740
3748 public function initAsSpecimen()
3749 {
3750 global $user;
3751
3752 $now = dol_now();
3753
3754 // Initialise parameters
3755 $this->id = 0;
3756 $this->ref = 'SPECIMEN';
3757 $this->specimen = 1;
3758 $this->user_creation_id = $user->id;
3759
3760 $this->lastname = 'DOLIBARR';
3761 $this->firstname = 'SPECIMEN';
3762 $this->gender = 'man';
3763 $this->note_public = 'This is a note public';
3764 $this->note_private = 'This is a note private';
3765 $this->email = 'email@specimen.com';
3766 $this->personal_email = 'personalemail@specimen.com';
3767 $this->socialnetworks = array(
3768 'skype' => 'skypepseudo',
3769 'twitter' => 'twitterpseudo',
3770 'facebook' => 'facebookpseudo',
3771 'linkedin' => 'linkedinpseudo',
3772 );
3773 $this->office_phone = '0999999999';
3774 $this->office_fax = '0999999998';
3775 $this->user_mobile = '0999999997';
3776 $this->personal_mobile = '0999999996';
3777 $this->admin = 0;
3778 $this->login = 'dolibspec';
3779 $this->pass = 'dolibSpec+@123';
3780 //$this->pass_indatabase='dolibspec'; Set after a fetch
3781 //$this->pass_indatabase_crypted='e80ca5a88c892b0aaaf7e154853bccab'; Set after a fetch
3782 $this->datec = $now;
3783 $this->datem = $now;
3784
3785 $this->datelastlogin = $now;
3786 $this->iplastlogin = '127.0.0.1';
3787 $this->datepreviouslogin = $now;
3788 $this->ippreviouslogin = '127.0.0.1';
3789 $this->status = 1;
3790
3791 $this->entity = 1;
3792
3793 return 1;
3794 }
3795
3802 public function info($id)
3803 {
3804 $sql = "SELECT u.rowid, u.login as ref, u.datec, fk_user_creat as user_creation_id, fk_user_modif as user_modification_id,";
3805 $sql .= " GREATEST(u.tms, uef.tms) as date_modification, u.entity";
3806 $sql .= " FROM ".$this->db->prefix()."user as u";
3807 $sql .= " LEFT JOIN ".$this->db->prefix()."user_extrafields as uef ON uef.fk_object = u.rowid";
3808 $sql .= " WHERE u.rowid = ".((int) $id);
3809
3810 $result = $this->db->query($sql);
3811 if ($result) {
3812 if ($this->db->num_rows($result)) {
3813 $obj = $this->db->fetch_object($result);
3814
3815 $this->id = $obj->rowid;
3816
3817 $this->user_creation_id = $obj->user_creation_id;
3818 $this->user_modification_id = $obj->user_modification_id;
3819
3820 $this->ref = (!$obj->ref) ? $obj->rowid : $obj->ref;
3821 $this->date_creation = $this->db->jdate($obj->datec);
3822 $this->date_modification = $this->db->jdate($obj->date_modification);
3823 $this->entity = $obj->entity;
3824 }
3825
3826 $this->db->free($result);
3827 } else {
3828 dol_print_error($this->db);
3829 }
3830 }
3831
3832
3838 public function getNbOfEMailings()
3839 {
3840 $sql = "SELECT count(mc.email) as nb";
3841 $sql .= " FROM ".$this->db->prefix()."mailing_cibles as mc";
3842 $sql .= " WHERE mc.email = '".$this->db->escape($this->email)."'";
3843 $sql .= " AND mc.statut NOT IN (-1,0)"; // -1 error, 0 not sent, 1 sent with success
3844
3845 $resql = $this->db->query($sql);
3846 if ($resql) {
3847 $obj = $this->db->fetch_object($resql);
3848 $nb = (int) $obj->nb;
3849
3850 $this->db->free($resql);
3851 return $nb;
3852 } else {
3853 $this->error = $this->db->error();
3854 return -1;
3855 }
3856 }
3857
3866 public function getNbOfUsers($limitTo, $option = '', $admin = -1)
3867 {
3868 $sql = "SELECT count(rowid) as nb";
3869 $sql .= " FROM ".$this->db->prefix()."user";
3870 if ($option == 'superadmin') {
3871 $sql .= " WHERE entity = 0";
3872 } else {
3873 $sql .= " WHERE entity IN (".getEntity('user', 0).")";
3874 if ($limitTo == 'active') {
3875 $sql .= " AND statut = 1";
3876 }
3877 }
3878 if ($admin >= 0) {
3879 $sql .= " AND admin = ".(int) $admin;
3880 }
3881
3882 $resql = $this->db->query($sql);
3883 if ($resql) {
3884 $obj = $this->db->fetch_object($resql);
3885 $nb = (int) $obj->nb;
3886
3887 $this->db->free($resql);
3888 return $nb;
3889 } else {
3890 $this->error = $this->db->lasterror();
3891 return -1;
3892 }
3893 }
3894
3895 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3902 public function update_ldap2dolibarr(&$ldapuser)
3903 {
3904 // phpcs:enable
3905 // TODO: See why the update sets all values to empty (does global $user overwrite?)
3906 global $user;
3907
3908 $socialnetworks = getArrayOfSocialNetworks();
3909
3910 $tmpvar = getDolGlobalString('LDAP_FIELD_FIRSTNAME');
3911 $this->firstname = $ldapuser->$tmpvar;
3912 $tmpvar = getDolGlobalString('LDAP_FIELD_NAME');
3913 $this->lastname = $ldapuser->$tmpvar;
3914 $tmpvar = getDolGlobalString('LDAP_FIELD_LOGIN');
3915 $this->login = $ldapuser->$tmpvar;
3916 $tmpvar = getDolGlobalString('LDAP_FIELD_PASSWORD');
3917 $this->pass = $ldapuser->$tmpvar;
3918 $tmpvar = getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED');
3919 $this->pass_indatabase_crypted = $ldapuser->$tmpvar;
3920
3921 $tmpvar = getDolGlobalString('LDAP_FIELD_PHONE');
3922 $this->office_phone = $ldapuser->$tmpvar;
3923 $tmpvar = getDolGlobalString('LDAP_FIELD_MOBILE');
3924 $this->user_mobile = $ldapuser->$tmpvar;
3925 $tmpvar = getDolGlobalString('LDAP_FIELD_FAX');
3926 $this->office_fax = $ldapuser->$tmpvar;
3927 $tmpvar = getDolGlobalString('LDAP_FIELD_MAIL');
3928 $this->email = $ldapuser->$tmpvar;
3929 foreach ($socialnetworks as $key => $value) {
3930 $tmpvar = getDolGlobalString('LDAP_FIELD_'.strtoupper($value['label']));
3931 $this->socialnetworks[$value['label']] = $ldapuser->$tmpvar;
3932 }
3933 $tmpvar = getDolGlobalString('LDAP_FIELD_SID');
3934 $this->ldap_sid = $ldapuser->$tmpvar;
3935
3936 $tmpvar = getDolGlobalString('LDAP_FIELD_TITLE');
3937 $this->job = $ldapuser->$tmpvar;
3938 $tmpvar = getDolGlobalString('LDAP_FIELD_DESCRIPTION');
3939 $this->note_public = $ldapuser->$tmpvar;
3940
3941 $result = $this->update($user);
3942
3943 dol_syslog(get_class($this)."::update_ldap2dolibarr result=".$result, LOG_DEBUG);
3944
3945 return $result;
3946 }
3947
3948
3949 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3956 public function get_children()
3957 {
3958 // phpcs:enable
3959 $sql = "SELECT rowid FROM ".$this->db->prefix()."user";
3960 $sql .= " WHERE fk_user = ".((int) $this->id);
3961
3962 dol_syslog(get_class($this)."::get_children", LOG_DEBUG);
3963 $res = $this->db->query($sql);
3964 if ($res) {
3965 $users = array();
3966 while ($rec = $this->db->fetch_array($res)) {
3967 $user = new User($this->db);
3968 $user->fetch($rec['rowid']);
3969 $users[] = $user;
3970 }
3971 return $users;
3972 } else {
3973 dol_print_error($this->db);
3974 return -1;
3975 }
3976 }
3977
3978
3984 private function loadParentOf()
3985 {
3986 $this->parentof = array();
3987
3988 // Load array[child]=parent
3989 $sql = "SELECT fk_user as id_parent, rowid as id_son";
3990 $sql .= " FROM ".$this->db->prefix()."user";
3991 $sql .= " WHERE fk_user <> 0";
3992 $sql .= " AND entity IN (".getEntity('user').")";
3993
3994 dol_syslog(get_class($this)."::loadParentOf", LOG_DEBUG);
3995 $resql = $this->db->query($sql);
3996 if ($resql) {
3997 while ($obj = $this->db->fetch_object($resql)) {
3998 $this->parentof[$obj->id_son] = $obj->id_parent;
3999 }
4000 return 1;
4001 } else {
4002 dol_print_error($this->db);
4003 return -1;
4004 }
4005 }
4006
4007 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4021 public function get_full_tree($deleteafterid = 0, $filter = '')
4022 {
4023 // phpcs:enable
4024 global $hookmanager;
4025
4026 // Actions hooked (by external module)
4027 $hookmanager->initHooks(array('userdao'));
4028
4029 $this->users = array();
4030
4031 // Init this->parentof that is array(id_son=>id_parent, ...)
4032 $this->loadParentOf();
4033
4034 // Init $this->users array
4035 $sql = "SELECT DISTINCT u.rowid, u.firstname, u.lastname, u.fk_user, u.fk_soc, u.login, u.email, u.gender, u.admin, u.statut, u.photo, u.entity"; // Distinct reduce pb with old tables with duplicates
4036 $sql .= " FROM ".$this->db->prefix()."user as u";
4037 // Add fields from hooks
4038 $parameters = array();
4039 $reshook = $hookmanager->executeHooks('printUserListWhere', $parameters); // Note that $action and $object may have been modified by hook
4040 if ($reshook > 0) {
4041 $sql .= $hookmanager->resPrint;
4042 } else {
4043 $sql .= " WHERE u.entity IN (".getEntity('user').")";
4044 }
4045 if ($filter) {
4046 $sql .= forgeSQLFromUniversalSearchCriteria($filter);
4047 }
4048
4049 dol_syslog(get_class($this)."::get_full_tree get user list", LOG_DEBUG);
4050 $resql = $this->db->query($sql);
4051 if ($resql) {
4052 $i = 0;
4053 while ($obj = $this->db->fetch_object($resql)) {
4054 $this->users[(int) $obj->rowid]
4055 = array(
4056 'rowid' => (int) $obj->rowid,
4057 'id' => (int) $obj->rowid,
4058 'fk_user' => (int) $obj->fk_user,
4059 'fk_soc' => (int) $obj->fk_soc,
4060 'firstname' => (string) $obj->firstname,
4061 'lastname' => (string) $obj->lastname,
4062 'login' => (string) $obj->login,
4063 'statut' => (int) $obj->statut,
4064 'entity' => (int) $obj->entity,
4065 'email' => (string) $obj->email,
4066 'gender' => (string) $obj->gender,
4067 'admin' => (int) $obj->admin,
4068 'photo' => (string) $obj->photo,
4069 // fields are filled with build_path_from_id_user
4070 'fullpath' => '',
4071 'fullname' => '',
4072 'level' => 0,
4073 );
4074 $i++;
4075 }
4076 } else {
4077 dol_print_error($this->db);
4078 return -1;
4079 }
4080
4081 // We add the fullpath property to each element of the first level (no parent exists)
4082 dol_syslog(get_class($this)."::get_full_tree call to build_path_from_id_user", LOG_DEBUG);
4083 foreach ($this->users as $key => $val) {
4084 $result = $this->build_path_from_id_user($key, 0); // Process a branch from the root user key (this user has no parent)
4085 if ($result < 0) {
4086 $this->error = 'ErrorLoopInHierarchy';
4087 return -1;
4088 }
4089 }
4090
4091 // Exclude leaf including $deleteafterid from tree
4092 if ($deleteafterid) {
4093 //print "Look to discard user ".$deleteafterid."\n";
4094 $keyfilter1 = '^'.$deleteafterid.'$';
4095 $keyfilter2 = '_'.$deleteafterid.'$';
4096 $keyfilter3 = '^'.$deleteafterid.'_';
4097 $keyfilter4 = '_'.$deleteafterid.'_';
4098 foreach (array_keys($this->users) as $key) {
4099 $fullpath = (string) $this->users[$key]['fullpath'];
4100 if (preg_match('/'.$keyfilter1.'/', $fullpath) || preg_match('/'.$keyfilter2.'/', $fullpath)
4101 || preg_match('/'.$keyfilter3.'/', $fullpath) || preg_match('/'.$keyfilter4.'/', $fullpath)) {
4102 unset($this->users[$key]);
4103 }
4104 }
4105 }
4106
4107 dol_syslog(get_class($this)."::get_full_tree dol_sort_array", LOG_DEBUG);
4108 $this->users = dol_sort_array($this->users, 'fullname', 'asc', 1, 0, 1);
4109
4110 return $this->users;
4111 }
4112
4121 public function getAllChildIds($addcurrentuser = 0)
4122 {
4123 $childids = array();
4124
4125 if (isset($this->cache_childids[$this->id])) {
4126 $childids = $this->cache_childids[$this->id];
4127 } else {
4128 // Init this->users
4129 $treeresult = $this->get_full_tree();
4130
4131 $idtoscan = $this->id;
4132
4133 dol_syslog("Build childid for id = ".$idtoscan);
4134 foreach ($this->users as $id => $val) {
4135 if (preg_match('/_'.$idtoscan.'_/', $val['fullpath'])) {
4136 $childids[$val['id']] = $val['id'];
4137 }
4138 }
4139
4140 // A loop anywhere in the hierarchy aborts get_full_tree(), leaving the branches it had not
4141 // walked yet with an empty fullpath, so they silently drop out of the list above. Do not
4142 // cache such a truncated result, it would be reused for the whole request.
4143 if ($treeresult < 0) {
4144 dol_syslog(get_class($this)."::getAllChildIds got a truncated tree: ".$this->error, LOG_WARNING);
4145 return $addcurrentuser ? array($this->id => $this->id) : $childids;
4146 }
4147 }
4148 $this->cache_childids[$this->id] = $childids;
4149
4150 if ($addcurrentuser) {
4151 $childids[$this->id] = $this->id;
4152 }
4153
4154 return $childids;
4155 }
4156
4157 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4166 public function build_path_from_id_user($id_user, $protection = 0)
4167 {
4168 // phpcs:enable
4169 //dol_syslog(get_class($this)."::build_path_from_id_user id_user=".$id_user." protection=".$protection, LOG_DEBUG);
4170
4171 if (!empty($this->users[$id_user]['fullpath'])) {
4172 // Already defined
4173 dol_syslog(get_class($this)."::build_path_from_id_user fullpath and fullname already defined", LOG_WARNING);
4174 return 0;
4175 }
4176
4177 // Define fullpath and fullname
4178 $this->users[$id_user]['fullpath'] = '_'.$id_user;
4179 $this->users[$id_user]['fullname'] = $this->users[$id_user]['lastname'];
4180 $i = 0;
4181 $cursor_user = $id_user;
4182
4183 $useridfound = array($id_user);
4184 while (!empty($this->parentof[$cursor_user]) && !empty($this->users[$this->parentof[$cursor_user]])) { // @phan-suppress-current-line PhanTypeMismatchProperty
4185 if (in_array($this->parentof[$cursor_user], $useridfound)) {
4186 dol_syslog("The hierarchy of user has a recursive loop", LOG_WARNING);
4187 return -1; // Should not happen. Protection against looping hierarchy
4188 }
4189 $useridfound[] = $this->parentof[$cursor_user];
4190 $this->users[$id_user]['fullpath'] = '_'.$this->parentof[$cursor_user].$this->users[$id_user]['fullpath'];
4191 $this->users[$id_user]['fullname'] = $this->users[$this->parentof[$cursor_user]]['lastname'].' >> '.$this->users[$id_user]['fullname'];
4192 $i++;
4193 $cursor_user = $this->parentof[$cursor_user];
4194 }
4195
4196 // We count number of _ to have level
4197 $this->users[$id_user]['level'] = dol_strlen(preg_replace('/[^_]/i', '', $this->users[$id_user]['fullpath']));
4198
4199 return 1;
4200 }
4201
4210 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
4211 {
4212 $tables = array(
4213 'user',
4214 );
4215
4216 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
4217 }
4218
4229 public static function replaceContact(DoliDB $dbs, $origin_id, $dest_id)
4230 {
4231 if (!CommonObject::commonReplaceContact($dbs, $origin_id, $dest_id, array('user'))) {
4232 return false;
4233 }
4234
4235 return CommonObject::commonReplaceContact($dbs, $origin_id, $dest_id, array('user_alert'), 'fk_contact');
4236 }
4237
4238
4244 public function loadStateBoard()
4245 {
4246 $this->nb = array();
4247
4248 $sql = "SELECT COUNT(DISTINCT u.rowid) as nb";
4249 $sql .= " FROM ".$this->db->prefix()."user as u";
4250 if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
4251 $sql .= ", ".$this->db->prefix()."usergroup_user as ug";
4252 $sql .= " WHERE ug.entity IN (".getEntity('usergroup').")";
4253 $sql .= " AND ug.fk_user = u.rowid";
4254 } else {
4255 $sql .= " WHERE u.entity IN (".getEntity('user').")";
4256 }
4257 $sql .= " AND u.statut > 0";
4258 //$sql.= " AND employee != 0";
4259
4260 $resql = $this->db->query($sql);
4261 if ($resql) {
4262 while ($obj = $this->db->fetch_object($resql)) {
4263 $this->nb["users"] = $obj->nb;
4264 }
4265 $this->db->free($resql);
4266 return 1;
4267 } else {
4268 dol_print_error($this->db);
4269 $this->error = $this->db->error();
4270 return -1;
4271 }
4272 }
4273
4285 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
4286 {
4287 global $langs;
4288
4289 $langs->load("user");
4290
4291 // Set the '$modele' to the name of the document template (model) to use
4292 if (!dol_strlen($modele)) {
4293 if (getDolGlobalString('USER_ADDON_PDF')) {
4294 $modele = getDolGlobalString('USER_ADDON_PDF');
4295 } else {
4296 $modele = 'bluesky';
4297 }
4298 }
4299
4300 $modelpath = "core/modules/user/doc/";
4301
4302 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
4303 }
4304
4305 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4313 public function user_get_property($rowid, $mode)
4314 {
4315 // phpcs:enable
4316 $user_property = '';
4317
4318 if (empty($rowid)) {
4319 return '';
4320 }
4321
4322 $sql = "SELECT rowid, email, user_mobile, civility, lastname, firstname";
4323 $sql .= " FROM ".$this->db->prefix()."user";
4324 $sql .= " WHERE rowid = ".((int) $rowid);
4325
4326 $resql = $this->db->query($sql);
4327 if ($resql) {
4328 $nump = $this->db->num_rows($resql);
4329
4330 if ($nump) {
4331 $obj = $this->db->fetch_object($resql);
4332
4333 if ($mode == 'email') {
4334 $user_property = dolGetFirstLastname($obj->firstname, $obj->lastname)." <".$obj->email.">";
4335 } elseif ($mode == 'mobile') {
4336 $user_property = $obj->user_mobile;
4337 } elseif ($mode == 'name') {
4338 $user_property = dolGetFirstLastname($obj->firstname, $obj->lastname);
4339 }
4340 }
4341 return $user_property;
4342 } else {
4343 dol_print_error($this->db);
4344 }
4345
4346 return '';
4347 }
4348
4356 public function getOnlineVirtualCardUrl($mode = '', $typeofurl = 'external')
4357 {
4359 global $conf;
4360
4361 $instanceuniqueid = empty($conf->file->instance_unique_id) ? '' : $conf->file->instance_unique_id;
4362 $encodedsecurekey = dol_hash($instanceuniqueid.'uservirtualcard'.$this->id.'-'.$this->login, 'md5');
4363 if (isModEnabled('multicompany')) {
4364 $entity_qr = '&entity='.((int) $conf->entity);
4365 } else {
4366 $entity_qr = '';
4367 }
4368 // Define $urlwithroot
4369 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
4370 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
4371 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
4372
4373 if ($typeofurl == 'internal') {
4374 $urlwithroot = DOL_URL_ROOT;
4375 }
4376
4377 return $urlwithroot.'/public/users/view.php?id='.$this->id.'&securekey='.$encodedsecurekey.$entity_qr.($mode ? '&mode='.urlencode($mode) : '');
4378 }
4379
4393 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $entityfilter = false)
4394 {
4395 global $conf, $user;
4396
4397 $sql = "SELECT t.rowid";
4398 $sql .= ' FROM '.$this->db->prefix().$this->table_element.' as t ';
4399
4400 if ($entityfilter) {
4401 if (getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
4402 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
4403 $sql .= " WHERE t.entity IS NOT NULL"; // Show all users
4404 } else {
4405 $sql .= " WHERE t.entity = 0 OR EXISTS (";
4406 $sql .= " SELECT ug.rowid FROM " . $this->db->prefix() . "usergroup_user as ug";
4407 $sql .= " WHERE ug.fk_user = t.rowid AND ug.entity IN (" . getEntity('usergroup') . "))";
4408 }
4409 } else {
4410 $sql .= " WHERE t.entity IN (".getEntity('user').")";
4411 }
4412 } else {
4413 $sql .= " WHERE 1 = 1";
4414 }
4415
4416 // Manage filter
4417 $errormessage = '';
4418 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
4419 if ($errormessage) {
4420 $this->errors[] = $errormessage;
4421 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
4422 return -1;
4423 }
4424
4425 $sql .= $this->db->order($sortfield, $sortorder);
4426 if ($limit) {
4427 $sql .= $this->db->plimit($limit + 1, $offset);
4428 }
4429
4430 dol_syslog(__METHOD__, LOG_DEBUG);
4431
4432 $resql = $this->db->query($sql);
4433 if ($resql) {
4434 $this->users = array();
4435 $num = $this->db->num_rows($resql);
4436 if ($num) {
4437 while ($obj = $this->db->fetch_object($resql)) {
4438 $line = new self($this->db);
4439 $result = $line->fetch($obj->rowid);
4440 if ($result > 0 && !empty($line->id)) {
4441 $this->users[$obj->rowid] = clone $line;
4442 }
4443 }
4444 $this->db->free($resql);
4445 }
4446 return $num;
4447 } else {
4448 $this->errors[] = $this->db->lasterror();
4449 return -1;
4450 }
4451 }
4452
4460 private $findUserIdByEmailCache;
4461
4472 public function findUserIdByEmail($email)
4473 {
4474 if (isset($this->findUserIdByEmailCache[$email])) {
4475 return $this->findUserIdByEmailCache[$email];
4476 }
4477
4478 $this->findUserIdByEmailCache[$email] = -1;
4479
4480 $sql = 'SELECT rowid';
4481 $sql .= ' FROM '.$this->db->prefix().'user';
4482 if (getDolGlobalString('AGENDA_DISABLE_EXACT_USER_EMAIL_COMPARE_FOR_EXTERNAL_CALENDAR')) {
4483 $sql .= " WHERE email LIKE '%".$this->db->escape($this->db->escapeforlike($email))."%'";
4484 } else {
4485 $sql .= " WHERE email = '".$this->db->escape($email)."'";
4486 }
4487 $sql .= ' LIMIT 1';
4488
4489 $resql = $this->db->query($sql);
4490 if (!$resql) {
4491 return -1;
4492 }
4493
4494 $obj = $this->db->fetch_object($resql);
4495 if (!$obj) {
4496 return -1;
4497 }
4498
4499 $this->findUserIdByEmailCache[$email] = (int) $obj->rowid;
4500
4501 return $this->findUserIdByEmailCache[$email];
4502 }
4503
4510 public function cloneRights($fromId, $toId)
4511 {
4512 if (empty($fromId) || empty($toId)) {
4513 return -1;
4514 }
4515
4516 $this->db->begin();
4517
4518 // delete default rights for UserTo
4519 $sqlDelete = "DELETE FROM ".$this->db->prefix()."user_rights";
4520 $sqlDelete .= " WHERE fk_user = ".((int) $toId);
4521
4522 dol_syslog(get_class($this)."::clone_rights (delete default permissions)", LOG_DEBUG);
4523
4524 if (!$this->db->query($sqlDelete)) {
4525 $this->db->rollback();
4526 return -1;
4527 }
4528
4529 // Construction of the insertion request
4530 $sql = "INSERT INTO ".$this->db->prefix()."user_rights (entity, fk_user, fk_id)";
4531 $sql .= " SELECT entity, ".((int) $toId).", fk_id";
4532 $sql .= " FROM ".$this->db->prefix()."user_rights src";
4533 $sql .= " WHERE fk_user = ".((int) $fromId);
4534 $sql .= " AND NOT EXISTS (";
4535 $sql .= " SELECT 1";
4536 $sql .= " FROM ".$this->db->prefix()."user_rights dest";
4537 $sql .= " WHERE dest.entity = src.entity";
4538 $sql .= " AND dest.fk_user = ".((int) $toId);
4539 $sql .= " AND dest.fk_id = src.fk_id";
4540 $sql .= " )";
4541
4542 dol_syslog(get_class($this)."::clone_rights", LOG_DEBUG);
4543
4544 // Execute request
4545 if (!$this->db->query($sql)) {
4546 $this->db->rollback();
4547 return -1;
4548 }
4549
4550 $this->db->commit();
4551 return 1;
4552 }
4553
4562 public function cloneCategories($fromId, $toId, $type = 'user')
4563 {
4564 $this->db->begin();
4565
4566 if (empty($type)) {
4567 $type = $this->table_element;
4568 }
4569
4570 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4571 $categorystatic = new Categorie($this->db);
4572
4573 $sql = "INSERT INTO ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type])." (fk_categorie, fk_user)";
4574 $sql .= " SELECT fk_categorie, ".((int) $toId)." FROM ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]);
4575 $sql .= " WHERE fk_user = ".((int) $fromId);
4576
4577 if (!$this->db->query($sql)) {
4578 $this->error = $this->db->lasterror();
4579 $this->db->rollback();
4580 return -1;
4581 }
4582
4583 $this->db->commit();
4584 return 1;
4585 }
4586}
global $dolibarr_main_url_root
$c
Definition line.php:346
$object ref
Definition info.php:90
Class to manage members of a foundation.
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,...
Class to manage categories.
fetch_optionals($rowid=null, $optionsArray=null)
Function to get extra fields of an object into $this->array_options This method is in most cases call...
fetchWarehouse($force_warehouse_id=0)
Load the warehouse of object, from id $this->warehouse_id or $this->fk_warehouse, into this->warehous...
commonGenerateDocument($modelspath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams=null)
Common function for all objects extending CommonObject for generating documents.
deleteExtraFields()
Delete all extra fields values for the current object.
static commonReplaceThirdparty(DoliDB $dbs, $origin_id, $dest_id, array $tables, $ignoreerrors=0)
Function used to replace a thirdparty id with another one.
insertExtraFields($trigger='', $userused=null)
Add/Update all extra fields values for the current object.
static commonReplaceContact(DoliDB $dbs, $origin_id, $dest_id, array $tables, $fieldname='fk_socpeople', $ignoreerrors=0)
Function used to replace a contact id with another one.
Class to manage contact/addresses.
Class for MyObject.
Class to manage Dolibarr database access.
Class to manage warehouses.
static showphoto($modulepart, $object, $width=100, $height=0, $caneditfield=0, $cssclass='photowithmargin', $imagesize='', $addlinktofullsize=1, $cache=0, $forcecapture='', $noexternsourceoverwrite=0, $usesharelinkifavailable=0)
Return HTML code to output a photo.
static loadAndInstantiate($id, $db, $conf, $langs, $user)
Locate, load and instantiate a password generator/validator model by its id (the value stored in USER...
Class to manage third parties objects (customers, suppliers, prospects...)
Class to manage translations.
Class to manage user groups.
Class to manage Dolibarr users.
fetch($id=0, $login='', $sid='', $loadpersonalconf=0, $entity=-1, $email='', $fk_socpeople=0, $use_email_oauth2=0)
Load a user from database with its id or ref (login).
SetInGroup($group, $entity, $notrigger=0)
Add user into a group.
LibStatut($status, $mode=0)
Return the label of a status of user (active, inactive)
loadRights($moduletag='', $forcereload=0)
Load permissions granted to a user->id into object user->rights.
get_children()
Return and array with all instantiated first level children users of current user.
static replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a thirdparty id with another one.
loadStateBoard()
Load metrics this->nb for dashboard.
hasRight($module, $permlevel1, $permlevel2='')
Return if a user has a permission.
info($id)
Load info of user object.
create_from_contact($contact, $login='', $password='')
Create a user from a contact object.
setstatus($status)
Change status of a user.
get_full_tree($deleteafterid=0, $filter='')
Build the hierarchy/tree of users into an array.
_load_ldap_info()
Initialize the info array (array of LDAP values) that will be used to call LDAP functions.
delrights($rid, $allmodule='', $allperms='', $entity=0, $notrigger=0)
Remove a right to the user.
update_last_login_date()
Update the user's last login date in the database.
__construct($db)
Constructor of the class.
RemoveFromGroup($group, $entity, $notrigger=0)
Remove a user from a group.
isNotIntoValidityDateRange()
Return a link with photo Use this->id,this->photo.
getNbOfUsers($limitTo, $option='', $admin=-1)
Return number of existing users.
set_default_rights()
Assign rights by default.
fetchAll($sortorder='', $sortfield='', $limit=0, $offset=0, $filter='', $filtermode='AND', $entityfilter=false)
Load all objects into $this->users.
getOnlineVirtualCardUrl($mode='', $typeofurl='external')
Return string with full Url to virtual card.
update($user, $notrigger=0, $nosyncmember=0, $nosyncmemberpass=0, $nosynccontact=0)
Update a user into database (and also password if this->pass is defined)
getLoginUrl($withpictoimg=0, $option='', $notooltip=0, $morecss='')
Return clickable link of login (optionally with picto)
setCategories($categories)
Sets object to supplied categories.
loadParentOf()
Load this->parentof that is array(id_son=>id_parent, ...)
setForcePasswordChange($user, $value)
Set force password change flag.
fetch_clicktodial()
Read clicktodial information for user.
build_path_from_id_user($id_user, $protection=0)
For user id_user and its children available in this->users, define property fullpath and fullname.
error()
Returns the last functional error when manipulating the object.
cloneCategories($fromId, $toId, $type='user')
Copy related categories to another object.
getAllChildIds($addcurrentuser=0)
Return list of all child user ids in hierarchy (all sublevels).
initAsSpecimen()
Initialise an instance with random values.
setPassword($user, $password='', $changelater=0, $notrigger=0, $nosyncmember=0, $passwordalreadycrypted=0, $flagdelsessionsbefore=1)
Change password of a user.
getNomUrl($withpictoimg=0, $option='', $infologin=0, $notooltip=0, $maxlen=24, $hidethirdpartylogo=0, $mode='', $morecss='', $save_lastsearch_value=-1)
Return a HTML link to the user card (with optionally the picto) Use this->id,this->lastname,...
clearrights()
Clear all permissions array of user.
update_clicktodial()
Update clicktodial info.
cloneRights($fromId, $toId)
Clone permissions of user.
isExternalUser()
Return if a user is an external user It replaces old syntax: if ($user->socid)
getLibStatut($mode=0)
Return the label of the status of user (active, inactive)
create_from_member($member, $login='')
Create a user into database from a member object.
_load_ldap_dn($info, $mode=0)
Returns the complete DN (Distinguished Name) string in the LDAP directory for the object.
loadDefaultValues()
Load default values from database table into property ->default_values.
getPhotoUrl($width, $height, $cssclass='', $imagesize='')
Return a link with photo Use this->id,this->photo.
isAdmin()
Return if a user is an admin user It replaces old syntax: if ($user->admin)
update_ldap2dolibarr(&$ldapuser)
Update user using data from the LDAP.
getrights($moduletag='', $forcereload=0)
Load permissions granted to a user->id into object user->rights TODO Remove this method.
user_get_property($rowid, $mode)
Return property of user from its id.
send_password($user, $password='', $changelater=0)
Send a new password (or instructions to reset it) by email.
getKanbanView($option='', $arraydata=null)
Return clickable link of object (optionally with picto)
getNbOfEMailings()
Return number of mass Emailing received by this contacts with its email.
addrights($rid, $allmodule='', $allperms='', $entity=0, $notrigger=0)
Add a right to the user.
create($user, $notrigger=0)
Create a user into database.
loadPersonalConf($entity=-1)
Load const values from database table user_param and set it into user->conf->XXX.
generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null)
Create a document onto disk according to template module.
findUserIdByEmail($email)
Find a user by the given e-mail and return it's user id when found.
getTooltipContentArray($params)
getTooltipContentArray
static replaceContact(DoliDB $dbs, $origin_id, $dest_id)
Function used to replace a contact id with another one when merging two contacts.
print $langs trans("Ref").' m titre as m m statut as status
Or an array listing all the potential status of the object: array: int of the status => translated la...
Definition index.php:169
if(! $sortfield) if(! $sortorder) $module
Definition list.php:193
getFullName($langs, $option=0, $nameorder=-1, $maxlen=0)
Return full name (civility+' '+name+' '+lastname)
setUpperOrLowerCase()
Set to upper or ucwords/lower if needed.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
global $mysoc
dol_get_first_hour($date, $gm='tzserver')
Return GMT time for first hour of a given GMT date (it removes hours, min and second part)
Definition date.lib.php:676
dol_get_last_hour($date, $gm='tzserver')
Return GMT time for last hour of a given GMT date (it replaces hours, min and second part to 23:59:59...
Definition date.lib.php:662
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as p label as s rowid as s nom as s email
Sender: Who sends the email ("Sender" has sent emails on behalf of "From").
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_buildlogin($lastname, $firstname)
Build a login from lastname, firstname.
dol_now($mode='gmt')
Return date for now.
getDolGlobalLoginBadCharUnauthorized()
Return the list of unauthorized characters in user logins.
dol_print_phone($phone, $countrycode='', $contactid=0, $socid=0, $addlink='', $separ="&nbsp;", $withpicto='', $titlealt='', $adddivfloat=0, $morecss='paddingright')
Format phone numbers according to country.
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto='UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
dolBuildUrl($url, $params=[], $addtoken=false, $anchor='')
Return path of url.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
dol_sort_array(&$array, $index, $order='asc', $natsort=0, $case_sensitive=0, $keepindex=0)
Advanced sort array by the value of a given key, which produces ascending (default) or descending out...
dolGetFirstLastname($firstname, $lastname, $nameorder=-1)
Return firstname and lastname in correct order.
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0, $forbiddenfields=array())
forgeSQLFromUniversalSearchCriteria
getArrayOfSocialNetworks()
Get array of social network dictionary.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
getUserRemoteIP($trusted=0)
Return the real IP of remote user.
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '...' if string larger than length.
isValidEmail($address, $acceptsupervisorkey=0, $acceptuserkey=0)
Return true if email syntax is ok.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
div refaddress div address
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
conf($dolibarr_main_document_root, $realpathconf=null)
Load conf file (file must exists)
Definition inc.php:431
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
dolGetLdapPasswordHash($password, $type='md5')
Returns a specific ldap hash of a password.
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.
dolDecrypt($chain, $key='', $patterntotest='')
Decode a string with a symmetric encryption.
dol_verifyHash($chain, $hash, $type='0')
Compute a hash and compare it to the given one For backward compatibility reasons,...
dolEncrypt($chain, $key='', $ciphering='', $forceseed='', $obfuscationmode='dolcrypt')
Encode a string with a symmetric encryption.