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 $this->force_pass_change = $obj->force_pass_change;
673 $this->datelastpassvalidation = $obj->datelastpassvalidation;
674 $this->api_key = dolDecrypt($obj->api_key);
675
676 $this->address = $obj->address;
677 $this->zip = $obj->zip;
678 $this->town = $obj->town;
679
680 $this->country_id = $obj->country_id;
681 $this->country_code = $obj->country_id ? $obj->country_code : '';
682 //$this->country = $obj->country_id?($langs->trans('Country'.$obj->country_code)!='Country'.$obj->country_code?$langs->transnoentities('Country'.$obj->country_code):$obj->country):'';
683
684 $this->state_id = $obj->state_id;
685 $this->state_code = $obj->state_code;
686 $this->state = ($obj->state != '-' ? $obj->state : '');
687
688 $this->office_phone = $obj->office_phone;
689 $this->office_fax = $obj->office_fax;
690 $this->user_mobile = $obj->user_mobile;
691 $this->personal_mobile = $obj->personal_mobile;
692 $this->email = $obj->email;
693 $this->email_oauth2 = $obj->email_oauth2;
694 $this->personal_email = $obj->personal_email;
695 $this->socialnetworks = ($obj->socialnetworks ? (array) json_decode($obj->socialnetworks, true) : array());
696 $this->user_creation_id = $obj->user_creation_id;
697 $this->user_modification_id = $obj->user_modification_id;
698
699 $this->job = $obj->job;
700 $this->signature = $obj->signature;
701 $this->admin = $obj->admin;
702 $this->note_public = $obj->note_public;
703 $this->note_private = $obj->note_private;
704
705 $this->statut = $obj->status; // deprecated
706 $this->status = $obj->status;
707
708 $this->photo = $obj->photo;
709 $this->openid = $obj->openid;
710 $this->lang = $obj->lang;
711 $this->entity = $obj->entity;
712
713 $this->accountancy_code_user_general = $obj->accountancy_code_user_general;
714 $this->accountancy_code = $obj->accountancy_code;
715
716 $this->thm = $obj->thm;
717 $this->tjm = $obj->tjm;
718 $this->salary = $obj->salary;
719 $this->salaryextra = $obj->salaryextra;
720 $this->weeklyhours = $obj->weeklyhours;
721 $this->color = $obj->color;
722 $this->dateemployment = $this->db->jdate($obj->dateemployment);
723 $this->dateemploymentend = $this->db->jdate($obj->dateemploymentend);
724
725 $this->datec = $this->db->jdate($obj->datec);
726 $this->datem = $this->db->jdate($obj->datem);
727 $this->datelastlogin = $this->db->jdate($obj->datel);
728 $this->datepreviouslogin = $this->db->jdate($obj->datep);
729 $this->flagdelsessionsbefore = $this->db->jdate($obj->flagdelsessionsbefore, 'gmt');
730 $this->iplastlogin = $obj->iplastlogin;
731 $this->ippreviouslogin = $obj->ippreviouslogin;
732 $this->datestartvalidity = $this->db->jdate($obj->datestartvalidity);
733 $this->dateendvalidity = $this->db->jdate($obj->dateendvalidity);
734
735 $this->socid = $obj->fk_soc;
736 $this->contact_id = $obj->fk_socpeople;
737 $this->fk_member = $obj->fk_member;
738 $this->fk_user = $obj->fk_user;
739 $this->fk_user_expense_validator = $obj->fk_user_expense_validator;
740 $this->fk_user_holiday_validator = $obj->fk_user_holiday_validator;
741
742 $this->default_range = $obj->default_range;
743 $this->default_c_exp_tax_cat = $obj->default_c_exp_tax_cat;
744 $this->fk_warehouse = $obj->fk_warehouse;
745 $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.
746 $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.
747 $this->fk_establishment = $obj->fk_establishment;
748 $this->label_establishment = $obj->label_establishment;
749
750 // Protection when module multicompany was set, admin was set to first entity and then, the module was disabled,
751 // in such case, this admin user must be admin for ALL entities.
752 if (!isModEnabled('multicompany') && $this->admin && $this->entity == 1) {
753 $this->entity = 0;
754 }
755
756 // If user is linked to a warehouse, we load it into memory
757 if (isModEnabled('stock') && getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && (!empty($this->fk_warehouse) || !empty($this->warehouse_id))) {
758 $this->fetchWarehouse();
759 }
760 // Retrieve all extrafield
761 // fetch optionals attributes and labels
762 $this->fetch_optionals();
763
764 $this->db->free($resql);
765 } else {
766 $this->error = "USERNOTFOUND";
767 dol_syslog(get_class($this)."::fetch user not found", LOG_DEBUG);
768
769 $this->db->free($resql);
770 return 0;
771 }
772 } else {
773 $this->error = $this->db->lasterror();
774 return -1;
775 }
776
777 // To get back the global configuration unique to the user
778 if ($loadpersonalconf) {
779 $result = $this->loadPersonalConf($entity);
780
781 $result = $this->loadDefaultValues();
782
783 if ($result < 0) {
784 $this->error = $this->db->lasterror();
785 return -3;
786 }
787 }
788
789 // Add option to allow an admin internal user to make quick debug for internal users. Not yet implemented completely.
790 // This is a special cas that is allowed to have a GETPOST inside a class.
791 if (GETPOSTINT('forceexternaluser') && $this->admin && empty($this->socid)) {
792 $this->socid = GETPOSTINT('forceexternaluser');
793 }
794
795 return 1;
796 }
797
798
805 public function loadPersonalConf($entity = -1)
806 {
807 global $conf;
808
809 // Load user->conf for user
810 $sql = "SELECT param, value FROM ".$this->db->prefix()."user_param";
811 $sql .= " WHERE fk_user = ".((int) $this->id);
812 if ($entity < 0) {
813 $sql .= " AND entity IN (0, ".((int) $conf->entity).")"; // IN (0, x)
814 } else {
815 $sql .= " AND entity = ".((int) $entity); // 0 or x
816 }
817
818 //dol_syslog(get_class($this).'::fetch load personalized conf', LOG_DEBUG);
819 $resql = $this->db->query($sql);
820 if ($resql) {
821 $num = $this->db->num_rows($resql);
822 $i = 0;
823 while ($i < $num) {
824 $obj = $this->db->fetch_object($resql);
825 $p = (!empty($obj->param) ? $obj->param : '');
826 if (!empty($p)) {
827 $this->conf->$p = $obj->value;
828 }
829 $i++;
830 }
831 $this->db->free($resql);
832
833 return $num;
834 } else {
835 $this->error = $this->db->lasterror();
836
837 return -2;
838 }
839 }
840
846 public function loadDefaultValues()
847 {
848 global $conf;
849
850 if (getDolGlobalString('MAIN_ENABLE_DEFAULT_VALUES')) {
851 // Load user->default_values for user. TODO Save this in memcached ?
852 require_once DOL_DOCUMENT_ROOT.'/core/class/defaultvalues.class.php';
853
854 $defaultValues = new DefaultValues($this->db);
855 $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)
856 //$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)
857
858 if (!is_array($result) && $result < 0) {
859 setEventMessages($defaultValues->error, $defaultValues->errors, 'errors');
860 dol_print_error($this->db);
861 return -1;
862 } elseif (count($result) > 0) {
863 foreach ($result as $defval) {
864 if (!empty($defval->page) && !empty($defval->type) && !empty($defval->param)) {
865 $pagewithoutquerystring = $defval->page;
866 $pagequeries = '';
867 $reg = array();
868 if (preg_match('/^([^\?]+)\?(.*)$/', $pagewithoutquerystring, $reg)) { // There is query param
869 $pagewithoutquerystring = $reg[1];
870 $pagequeries = $reg[2];
871 }
872 $this->default_values[$pagewithoutquerystring][$defval->type][$pagequeries ? $pagequeries : '_noquery_'][$defval->param] = $defval->value;
873 }
874 }
875 }
876 if (!empty($this->default_values)) {
877 foreach ($this->default_values as $a => $b) {
878 foreach ($b as $c => $d) {
879 krsort($this->default_values[$a][$c]);
880 }
881 }
882 }
883 }
884 return 1;
885 }
886
893 public function isAdmin()
894 {
895 return $this->admin;
896 }
897
904 public function isExternalUser()
905 {
906 return $this->socid;
907 }
908
920 public function hasRight($module, $permlevel1, $permlevel2 = '')
921 {
922 // For compatibility with bad naming permissions on module
923 $moduletomoduletouse = array(
924 'category' => 'categorie',
925 'compta' => 'comptabilite',
926 'contract' => 'contrat',
927 'member' => 'adherent',
928 'mo' => 'mrp',
929 'order' => 'commande',
930 'produit' => 'product',
931 'productlot' => 'product',
932 'project' => 'projet',
933 'propale' => 'propal',
934 'shipping' => 'expedition',
935 'task' => 'task@projet',
936 'fichinter' => 'ficheinter',
937 'intervention' => 'ficheinter',
938 'inventory' => 'stock',
939 'invoice' => 'facture',
940 'invoice_supplier' => 'facture@fournisseur',
941 'order_supplier' => 'fournisseur',
942 'knowledgerecord' => 'knowledgerecord@knowledgemanagement',
943 'skill@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all"
944 'job@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all"
945 'position@hrm' => 'all@hrm', // skill / job / position objects rights are for the moment grouped into right level "all"
946 'facturerec' => 'facture',
947 'margins' => 'margin',
948 );
949
950 if (!empty($moduletomoduletouse[$module])) {
951 $module = $moduletomoduletouse[$module];
952 }
953
954 // Compatibility layer for the supplier module split transition (MAIN_USE_NEW_SUPPLIERMOD).
955 // Allows both old and new permission syntaxes to work in parallel during migration.
956 // - Old: $user->hasRight('fournisseur', 'commande', 'lire')
957 // - New: $user->hasRight('supplier_order', 'lire')
958 // External modules are also transparently supported without any change on their side.
959 if (getDolGlobalInt('MAIN_USE_NEW_SUPPLIERMOD')) {
960 // New module names introduced by the split, mapped to their legacy equivalent.
961 // Format: 'new_module' => ['legacy_module', 'legacy_permlevel1']
962 $supplierNewToLegacy = array(
963 'supplier_order' => array('fournisseur', 'commande'),
964 'supplier_invoice' => array('fournisseur', 'facture'),
965 );
966
967 if (isset($supplierNewToLegacy[$module])) {
968 // Caller used new syntax: rewrite to legacy so the rights object resolves correctly.
969 // e.g. hasRight('supplier_order', 'lire') -> hasRight('fournisseur', 'commande', 'lire')
970 $permlevel2 = $permlevel1;
971 $permlevel1 = $supplierNewToLegacy[$module][1]; // e.g. 'commande'
972 $module = $supplierNewToLegacy[$module][0]; // e.g. 'fournisseur'
973 }
974 } else {
975 // Legacy mode: translate new module names back to old ones in case some
976 // updated code calls the new syntax while the option is not yet enabled.
977 $supplierLegacyCompat = array(
978 'supplier_order' => 'fournisseur',
979 'supplier_invoice' => 'fournisseur',
980 );
981
982 if (isset($supplierLegacyCompat[$module])) {
983 // e.g. hasRight('supplier_order', 'lire') stays routed through 'fournisseur'
984 $module = $supplierLegacyCompat[$module];
985 }
986 }
987
988 $moduleRightsMapping = array(
989 'product' => 'produit',
990 'margin' => 'margins',
991 'comptabilite' => 'compta'
992 );
993
994 $rightsPath = $module;
995 if (!empty($moduleRightsMapping[$rightsPath])) {
996 $rightsPath = $moduleRightsMapping[$rightsPath];
997 }
998
999 // If module is abc@module, we check permission user->hasRight(module, abc, permlevel1)
1000 $tmp = explode('@', $rightsPath, 2);
1001 if (!empty($tmp[1])) {
1002 if (strpos($module, '@') !== false) {
1003 $module = $tmp[1];
1004 }
1005 if ($tmp[0] != $tmp[1]) {
1006 // If $module = 'myobject@mymodule'
1007 $rightsPath = $tmp[1];
1008 $permlevel2 = $permlevel1;
1009 $permlevel1 = $tmp[0];
1010 } else {
1011 // If $module = 'abc@abc'
1012 $rightsPath = $tmp[1];
1013 }
1014 }
1015
1016 // In $conf->modules, we have 'accounting', 'product', 'facture', ...
1017 // In $user->rights, we have 'accounting', 'produit', 'facture', ...
1018
1019 if (!isModEnabled($module)) {
1020 return 0;
1021 }
1022
1023 // Special case for external user
1024 if (!empty($this->socid)) {
1025 if ($module == 'societe' && ($permlevel1 == 'creer' || $permlevel1 == 'write')) {
1026 return 0; // An external user never has the permission ->societe->write to see all thirdparties (always restricted to himself)
1027 }
1028 if ($module == 'societe' && $permlevel1 == 'client' && $permlevel2 == 'voir') {
1029 return 0; // An external user never has the permission ->societe->client->voir to see all thirdparties (always restricted to himself)
1030 }
1031 if ($module == 'societe' && $permlevel1 == 'export') {
1032 return 0; // An external user never has the permission ->societe->export to see all thirdparties (always restricted to himself)
1033 }
1034 if ($module == 'societe' && ($permlevel1 == 'supprimer' || $permlevel1 == 'delete')) {
1035 return 0; // An external user never has the permission ->societe->delete to see all thirdparties (always restricted to himself)
1036 }
1037 }
1038
1039 // For compatibility with bad naming permissions on permlevel1
1040 if ($permlevel1 == 'propale') {
1041 $permlevel1 = 'propal';
1042 }
1043 if ($permlevel1 == 'member') {
1044 $permlevel1 = 'adherent';
1045 }
1046 if ($permlevel1 == 'recruitmentcandidature') {
1047 $permlevel1 = 'recruitmentjobposition';
1048 }
1049
1050 if (empty($rightsPath) || empty($this->rights) || empty($this->rights->$rightsPath) || empty($permlevel1)) {
1051 return 0;
1052 }
1053
1054 if ($permlevel2) {
1055 if (!empty($this->rights->$rightsPath->$permlevel1)) {
1056 if (!empty($this->rights->$rightsPath->$permlevel1->$permlevel2)) {
1057 return $this->rights->$rightsPath->$permlevel1->$permlevel2;
1058 }
1059 // For backward compatibility with old permissions called "lire", "creer", "create", "supprimer"
1060 // instead of "read", "write", "delete"
1061 if ($permlevel2 == 'read' && !empty($this->rights->$rightsPath->$permlevel1->lire)) {
1062 return $this->rights->$rightsPath->$permlevel1->lire;
1063 }
1064 if ($permlevel2 == 'write' && !empty($this->rights->$rightsPath->$permlevel1->creer)) {
1065 return $this->rights->$rightsPath->$permlevel1->creer;
1066 }
1067 if ($permlevel2 == 'write' && !empty($this->rights->$rightsPath->$permlevel1->create)) {
1068 return $this->rights->$rightsPath->$permlevel1->create;
1069 }
1070 if ($permlevel2 == 'delete' && !empty($this->rights->$rightsPath->$permlevel1->supprimer)) {
1071 return $this->rights->$rightsPath->$permlevel1->supprimer;
1072 }
1073 }
1074 } else {
1075 if (!empty($this->rights->$rightsPath->$permlevel1)) {
1076 return $this->rights->$rightsPath->$permlevel1;
1077 }
1078 // For backward compatibility with old permissions called "lire", "creer", "create", "supprimer"
1079 // instead of "read", "write", "delete"
1080 if ($permlevel1 == 'read' && !empty($this->rights->$rightsPath->lire)) {
1081 return $this->rights->$rightsPath->lire;
1082 }
1083 if ($permlevel1 == 'write' && !empty($this->rights->$rightsPath->creer)) {
1084 return $this->rights->$rightsPath->creer;
1085 }
1086 if ($permlevel1 == 'write' && !empty($this->rights->$rightsPath->create)) {
1087 return $this->rights->$rightsPath->create;
1088 }
1089 if ($permlevel1 == 'delete' && !empty($this->rights->$rightsPath->supprimer)) {
1090 return $this->rights->$rightsPath->supprimer;
1091 }
1092 }
1093
1094 return 0;
1095 }
1096
1108 public function addrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
1109 {
1110 global $conf, $user, $langs;
1111
1112 $entity = (empty($entity) ? $conf->entity : $entity);
1113
1114 dol_syslog(get_class($this)."::addrights $rid, $allmodule, $allperms, $entity, $notrigger for user id=".$this->id);
1115
1116 if (empty($this->id)) {
1117 $this->error = 'Try to call addrights on an object user with an empty id';
1118 return -1;
1119 }
1120
1121 $error = 0;
1122 $whereforadd = '';
1123
1124 $this->db->begin();
1125
1126 if (!empty($rid)) {
1127 $module = $perms = $subperms = '';
1128
1129 // If we ask to add a given permission, we first load properties of this permission (module, perms and subperms).
1130 $sql = "SELECT module, perms, subperms";
1131 $sql .= " FROM ".$this->db->prefix()."rights_def";
1132 $sql .= " WHERE id = ".((int) $rid);
1133 $sql .= " AND entity = ".((int) $entity);
1134
1135 $result = $this->db->query($sql);
1136 if ($result) {
1137 $obj = $this->db->fetch_object($result);
1138
1139 if ($obj) {
1140 $module = $obj->module;
1141 $perms = $obj->perms;
1142 $subperms = $obj->subperms;
1143 }
1144 } else {
1145 $error++;
1146 dol_print_error($this->db);
1147 }
1148
1149 // Define the where for the permission to add
1150 $whereforadd = "id=".((int) $rid);
1151 // Add also inherited permissions
1152 if (!empty($subperms)) {
1153 $whereforadd .= " OR (module='".$this->db->escape($module)."' AND perms='".$this->db->escape($perms)."' AND (subperms='lire' OR subperms='read'))";
1154 } elseif (!empty($perms)) {
1155 $whereforadd .= " OR (module='".$this->db->escape($module)."' AND (perms='lire' OR perms='read') AND (subperms IS NULL or subperms = ''))";
1156 }
1157 } else {
1158 // A list of permission was requested (not a single specific permission)
1159 // based on the name of a module of permissions
1160 // Used in the where clause to determine the list of permissions to add.
1161 if (!empty($allmodule)) {
1162 if ($allmodule == 'allmodules') {
1163 $whereforadd = 'allmodules';
1164 } else {
1165 $whereforadd = "module='".$this->db->escape($allmodule)."'";
1166 if (!empty($allperms)) {
1167 $whereforadd .= " AND perms='".$this->db->escape($allperms)."'";
1168 }
1169 }
1170 }
1171 }
1172
1173 // Add automatically other permission using the criteria whereforadd
1174 // $whereforadd can be a SQL filter or the string 'allmodules'
1175 if (!empty($whereforadd)) {
1176 //print "$module-$perms-$subperms";
1177 $sql = "SELECT id";
1178 $sql .= " FROM ".$this->db->prefix()."rights_def";
1179 $sql .= " WHERE entity = ".((int) $entity);
1180 if (!empty($whereforadd) && $whereforadd != 'allmodules') {
1181 $sql .= " AND (".$whereforadd.")"; // Note: parenthesis are important because whereforadd can contains OR. Also note that $whereforadd is already sanitized
1182 }
1183
1184 $sqldelete = "DELETE FROM ".$this->db->prefix()."user_rights";
1185 $sqldelete .= " WHERE fk_user = ".((int) $this->id)." AND fk_id IN (";
1186 $sqldelete .= $sql;
1187 $sqldelete .= ") AND entity = ".((int) $entity);
1188 if (!$this->db->query($sqldelete)) {
1189 $error++;
1190 }
1191
1192 if (!$error) {
1193 $resql = $this->db->query($sql);
1194 if ($resql) {
1195 $num = $this->db->num_rows($resql);
1196 $i = 0;
1197 while ($i < $num) {
1198 $obj = $this->db->fetch_object($resql);
1199
1200 if ($obj) {
1201 $nid = $obj->id;
1202
1203 $sql = "INSERT INTO ".$this->db->prefix()."user_rights (entity, fk_user, fk_id) VALUES (".((int) $entity).", ".((int) $this->id).", ".((int) $nid).")";
1204 if (!$this->db->query($sql)) {
1205 $error++;
1206 }
1207 }
1208
1209 $i++;
1210 }
1211 } else {
1212 $error++;
1213 dol_print_error($this->db);
1214 }
1215 }
1216 }
1217
1218 if (!$error && !$notrigger) {
1219 $langs->load("other");
1220 $this->context = array('audit' => $langs->trans("PermissionsAdd").($rid ? ' (id='.$rid.')' : ''));
1221
1222 // Call trigger
1223 $result = $this->call_trigger('USER_MODIFY', $user);
1224 if ($result < 0) {
1225 $error++;
1226 }
1227 // End call triggers
1228 }
1229
1230 if ($error) {
1231 $this->db->rollback();
1232 return -$error;
1233 } else {
1234 $this->db->commit();
1235 return 1;
1236 }
1237 }
1238
1239
1251 public function delrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
1252 {
1253 global $conf, $user, $langs;
1254
1255 $error = 0;
1256 $wherefordel = '';
1257 $entity = (!empty($entity) ? $entity : $conf->entity);
1258
1259 $this->db->begin();
1260
1261 if (!empty($rid)) {
1262 $module = $perms = $subperms = '';
1263
1264 // When the request is to delete a specific permissions, this gets the
1265 // characteristics for the module, permissions and sub-permission of this permission.
1266 $sql = "SELECT module, perms, subperms";
1267 $sql .= " FROM ".$this->db->prefix()."rights_def";
1268 $sql .= " WHERE id = ".((int) $rid);
1269 $sql .= " AND entity IN (".$this->db->sanitize($entity, 0, 0, 0, 0).")";
1270
1271 $result = $this->db->query($sql);
1272 if ($result) {
1273 $obj = $this->db->fetch_object($result);
1274
1275 if ($obj) {
1276 $module = $obj->module;
1277 $perms = $obj->perms;
1278 $subperms = $obj->subperms;
1279 }
1280 } else {
1281 $error++;
1282 dol_print_error($this->db);
1283 }
1284
1285 // Where clause for the list of permissions to delete
1286 $wherefordel = "id=".((int) $rid);
1287 // Removal of induced rights
1288 if ($subperms == 'lire' || $subperms == 'read') {
1289 $wherefordel .= " OR (module='".$this->db->escape($module)."' AND perms='".$this->db->escape($perms)."' AND subperms IS NOT NULL)";
1290 }
1291 if ($perms == 'lire' || $perms == 'read') {
1292 $wherefordel .= " OR (module='".$this->db->escape($module)."')";
1293 }
1294 } else {
1295 // The deletion of the permissions concerns the name of a module or
1296 // list of permissions.
1297 // Used in the Where clause to determine the list of permission to delete
1298 if (!empty($allmodule)) {
1299 if ($allmodule == 'allmodules') {
1300 $wherefordel = 'allmodules';
1301 } else {
1302 $wherefordel = "module='".$this->db->escape($allmodule)."'";
1303 if (!empty($allperms)) {
1304 $wherefordel .= " AND perms='".$this->db->escape($allperms)."'";
1305 }
1306 }
1307 }
1308 }
1309
1310 // Delete permission according to a criteria set into $wherefordel
1311 if (!empty($wherefordel)) {
1312 //print "$module-$perms-$subperms";
1313 $sql = "SELECT id";
1314 $sql .= " FROM ".$this->db->prefix()."rights_def";
1315 $sql .= " WHERE entity IN (".$this->db->sanitize($entity, 0, 0, 0, 0).")";
1316 if (!empty($wherefordel) && $wherefordel != 'allmodules') {
1317 $sql .= " AND (".$wherefordel.")"; // Note: parenthesis are important because wherefordel can contains OR. Also note that $wherefordel is already sanitized
1318 }
1319
1320 // avoid admin to remove his own important rights
1321 if ($this->admin == 1) {
1322 $sql .= " AND id NOT IN (251, 252, 253, 254, 255, 256)"; // other users rights
1323 $sql .= " AND id NOT IN (341, 342, 343, 344)"; // own rights
1324 $sql .= " AND id NOT IN (351, 352, 353, 354)"; // groups rights
1325 $sql .= " AND id NOT IN (358)"; // user export
1326 }
1327
1328 $sqldelete = "DELETE FROM ".$this->db->prefix()."user_rights";
1329 $sqldelete .= " WHERE fk_user = ".((int) $this->id)." AND fk_id IN (";
1330 $sqldelete .= $sql;
1331 $sqldelete .= ")";
1332 $sqldelete .= " AND entity IN (".$this->db->sanitize($entity, 0, 0, 0, 0).")";
1333
1334 $resql = $this->db->query($sqldelete);
1335 if (!$resql) {
1336 $error++;
1337 dol_print_error($this->db);
1338 }
1339 }
1340
1341 if (!$error && !$notrigger) {
1342 $langs->load("other");
1343 $this->context = array('audit' => $langs->trans("PermissionsDelete").($rid ? ' (id='.$rid.')' : ''));
1344
1345 // Call trigger
1346 $result = $this->call_trigger('USER_MODIFY', $user);
1347 if ($result < 0) {
1348 $error++;
1349 }
1350 // End call triggers
1351 }
1352
1353 if ($error) {
1354 $this->db->rollback();
1355 return -$error;
1356 } else {
1357 $this->db->commit();
1358 return 1;
1359 }
1360 }
1361
1362
1369 public function clearrights()
1370 {
1371 dol_syslog(get_class($this)."::clearrights reset user->rights");
1372 $this->rights = new stdClass();
1373 $this->nb_rights = 0;
1374 $this->all_permissions_are_loaded = 0;
1375 $this->_tab_loaded = array();
1376 }
1377
1378
1387 public function loadRights($moduletag = '', $forcereload = 0)
1388 {
1389 global $conf;
1390
1391 $alreadyloaded = false;
1392
1393 if (empty($forcereload)) {
1394 if ($moduletag && isset($this->_tab_loaded[$moduletag]) && $this->_tab_loaded[$moduletag]) {
1395 // Rights for this module are already loaded, so we leave
1396 $alreadyloaded = true;
1397 }
1398
1399 if (!empty($this->all_permissions_are_loaded)) {
1400 // We already loaded all rights for this user, so we leave
1401 $alreadyloaded = true;
1402 }
1403 }
1404
1405 // More init to avoid warnings/errors
1406 if (!isset($this->rights) || !is_object($this->rights)) {
1407 $this->rights = new stdClass();
1408 }
1409 if (!isset($this->rights->user) || !is_object($this->rights->user)) {
1410 $this->rights->user = new stdClass();
1411 }
1412
1413 // Get permission of users + Get permissions of groups
1414
1415 if (!$alreadyloaded) {
1416 // First user permissions
1417 $sql = "SELECT DISTINCT r.module, r.module_origin, r.perms, r.subperms";
1418 $sql .= " FROM ".$this->db->prefix()."user_rights as ur,";
1419 $sql .= " ".$this->db->prefix()."rights_def as r";
1420 $sql .= " WHERE r.id = ur.fk_id";
1421 if (getDolGlobalString('MULTICOMPANY_BACKWARD_COMPATIBILITY')) {
1422 // On old version, we used entity defined into table r only
1423 // @FIXME Test on MULTICOMPANY_BACKWARD_COMPATIBILITY is a very strange business rules because the select should be always the
1424 // same than into user->loadRights() in user/perms.php and user/group/perms.php
1425 // We should never use and remove this case.
1426 $sql .= " AND r.entity IN (0,".(isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE') ? "1," : "").((int) $conf->entity).")";
1427 } else {
1428 // On table r=rights_def, the unique key is (id, entity) because id is hard coded into module descriptor and inserted during module activation.
1429 // So we must include the filter on entity on both table r. and ur.
1430 $sql .= " AND r.entity = ".((int) $conf->entity)." AND ur.entity = ".((int) $conf->entity);
1431 }
1432 $sql .= " AND ur.fk_user = ".((int) $this->id);
1433 $sql .= " AND r.perms IS NOT NULL";
1434 if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
1435 $sql .= " AND r.perms NOT LIKE '%_advance'"; // Hide advanced perms if option is not enabled
1436 }
1437 if ($moduletag) {
1438 $sql .= " AND r.module = '".$this->db->escape($moduletag)."'";
1439 }
1440
1441 $resql = $this->db->query($sql);
1442 if ($resql) {
1443 $num = $this->db->num_rows($resql);
1444 $i = 0;
1445 while ($i < $num) {
1446 $obj = $this->db->fetch_object($resql);
1447
1448 if ($obj) {
1449 // module_origin (set only when the right was declared by another module
1450 // via KEY_MODULE, to be filed into a foreign module's section of the
1451 // permission grid) is the namespace actually used to check the right with
1452 // hasRight(), so the declaring module keeps control of it regardless of
1453 // which module's section it is grouped under for display.
1454 $module = (!empty($obj->module_origin) ? $obj->module_origin : $obj->module);
1455 $perms = $obj->perms;
1456 $subperms = $obj->subperms;
1457
1458 if (!empty($perms)) {
1459 if (!empty($module)) {
1460 if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
1461 $this->rights->$module = new stdClass();
1462 }
1463 if (!empty($subperms)) {
1464 if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1465 $this->rights->$module->$perms = new stdClass();
1466 }
1467 if (empty($this->rights->$module->$perms->$subperms)) { // if not already counted
1468 $this->nb_rights++;
1469 }
1470 $this->rights->$module->$perms->$subperms = 1;
1471 } else {
1472 if (empty($this->rights->$module->$perms)) { // if not already counted
1473 $this->nb_rights++;
1474 }
1475 $this->rights->$module->$perms = 1;
1476 }
1477 }
1478 }
1479 }
1480 $i++;
1481 }
1482 $this->db->free($resql);
1483 }
1484
1485 // Now permissions of groups
1486 $sql = "SELECT DISTINCT r.module, r.module_origin, r.perms, r.subperms, r.entity";
1487 $sql .= " FROM ".$this->db->prefix()."usergroup_rights as gr,";
1488 $sql .= " ".$this->db->prefix()."usergroup_user as gu,";
1489 $sql .= " ".$this->db->prefix()."rights_def as r";
1490 $sql .= " WHERE r.id = gr.fk_id";
1491 if (getDolGlobalString('MULTICOMPANY_BACKWARD_COMPATIBILITY')) {
1492 // @FIXME Test on MULTICOMPANY_BACKWARD_COMPATIBILITY is a very strange business rules because the select should be always the
1493 // same than into user->loadRights() in user/perms.php and user/group/perms.php
1494 // We should never use and remove this case.
1495 if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
1496 $sql .= " AND gu.entity IN (0,".((int) $conf->entity).")";
1497 } else {
1498 $sql .= " AND r.entity = ".((int) $conf->entity);
1499 }
1500 } else {
1501 $sql .= " AND gr.entity = ".((int) $conf->entity); // Only groups created in current entity
1502 // The entity on the table gu=usergroup_user should be useless and should never be used because it is already into gr and r.
1503 // but when using MULTICOMPANY_TRANSVERSE_MODE, we may have inserted record that make rubbish result here due to the duplicate record of
1504 // other entities, so we are forced to add a filter on gu here
1505 $sql .= " AND gu.entity IN (0,".((int) $conf->entity).")";
1506 $sql .= " AND r.entity = ".((int) $conf->entity); // Only permission of modules enabled in current entity
1507 }
1508 // End of strange business rule
1509 $sql .= " AND gr.fk_usergroup = gu.fk_usergroup";
1510 $sql .= " AND gu.fk_user = ".((int) $this->id);
1511 $sql .= " AND r.perms IS NOT NULL";
1512 if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
1513 $sql .= " AND r.perms NOT LIKE '%_advance'"; // Hide advanced perms if option is not enabled
1514 }
1515 if ($moduletag) {
1516 $sql .= " AND r.module = '".$this->db->escape($moduletag)."'";
1517 }
1518
1519 $resql = $this->db->query($sql);
1520 if ($resql) {
1521 $num = $this->db->num_rows($resql);
1522 $i = 0;
1523 while ($i < $num) {
1524 $obj = $this->db->fetch_object($resql);
1525
1526 if ($obj) {
1527 // module_origin (set only when the right was declared by another module
1528 // via KEY_MODULE, to be filed into a foreign module's section of the
1529 // permission grid) is the namespace actually used to check the right with
1530 // hasRight(), so the declaring module keeps control of it regardless of
1531 // which module's section it is grouped under for display.
1532 $module = (!empty($obj->module_origin) ? $obj->module_origin : $obj->module);
1533 $perms = $obj->perms;
1534 $subperms = $obj->subperms;
1535
1536 if (!empty($perms)) {
1537 if (!empty($module)) {
1538 if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
1539 $this->rights->$module = new stdClass();
1540 }
1541 if (!empty($subperms)) {
1542 if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1543 $this->rights->$module->$perms = new stdClass();
1544 }
1545 if (empty($this->rights->$module->$perms->$subperms)) { // if not already counted
1546 $this->nb_rights++;
1547 }
1548 $this->rights->$module->$perms->$subperms = 1;
1549 } else {
1550 // 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
1551 if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1552 if (empty($this->rights->$module->$perms)) { // if not already counted
1553 $this->nb_rights++;
1554 }
1555 $this->rights->$module->$perms = 1;
1556 }
1557 }
1558 }
1559 }
1560 }
1561 $i++;
1562 }
1563 $this->db->free($resql);
1564 }
1565
1566 // Force permission on user for admin
1567 if (!empty($this->admin)) {
1568 if (empty($this->rights->user->user)) {
1569 $this->rights->user->user = new stdClass();
1570 }
1571 $listofpermtotest = array('lire', 'creer', 'password', 'supprimer', 'export');
1572 foreach ($listofpermtotest as $permtotest) {
1573 if (empty($this->rights->user->user->$permtotest)) {
1574 $this->rights->user->user->$permtotest = 1;
1575 $this->nb_rights++;
1576 }
1577 }
1578 if (empty($this->rights->user->self)) {
1579 $this->rights->user->self = new stdClass();
1580 }
1581 $listofpermtotest = array('creer', 'password');
1582 foreach ($listofpermtotest as $permtotest) {
1583 if (empty($this->rights->user->self->$permtotest)) {
1584 $this->rights->user->self->$permtotest = 1;
1585 $this->nb_rights++;
1586 }
1587 }
1588 // Add test on advanced permissions
1589 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS')) {
1590 if (empty($this->rights->user->user_advance)) {
1591 $this->rights->user->user_advance = new stdClass();
1592 }
1593 $listofpermtotest = array('readperms', 'write');
1594 foreach ($listofpermtotest as $permtotest) {
1595 if (empty($this->rights->user->user_advance->$permtotest)) {
1596 $this->rights->user->user_advance->$permtotest = 1;
1597 $this->nb_rights++;
1598 }
1599 }
1600 if (empty($this->rights->user->self_advance)) {
1601 $this->rights->user->self_advance = new stdClass();
1602 }
1603 $listofpermtotest = array('readperms', 'writeperms');
1604 foreach ($listofpermtotest as $permtotest) {
1605 if (empty($this->rights->user->self_advance->$permtotest)) {
1606 $this->rights->user->self_advance->$permtotest = 1;
1607 $this->nb_rights++;
1608 }
1609 }
1610 if (empty($this->rights->user->group_advance)) {
1611 $this->rights->user->group_advance = new stdClass();
1612 }
1613 $listofpermtotest = array('read', 'readperms', 'write', 'delete');
1614 foreach ($listofpermtotest as $permtotest) {
1615 if (empty($this->rights->user) || empty($this->rights->user->group_advance->$permtotest)) {
1616 $this->rights->user->group_advance->$permtotest = 1;
1617 $this->nb_rights++;
1618 }
1619 }
1620 }
1621 }
1622
1623 // For backward compatibility
1624 if (isset($this->rights->propale) && !isset($this->rights->propal)) {
1625 $this->rights->propal = $this->rights->propale;
1626 }
1627 if (isset($this->rights->propal) && !isset($this->rights->propale)) {
1628 $this->rights->propale = $this->rights->propal;
1629 }
1630
1631 if (!$moduletag) {
1632 // If the module was not define, then everything is loaded.
1633 // Therefore, we can consider that the permissions are cached
1634 // because they were all loaded for this user instance.
1635 $this->all_permissions_are_loaded = 1;
1636 } else {
1637 // If the module is defined, we flag it as loaded into cache
1638 $this->_tab_loaded[$moduletag] = 1;
1639 }
1640 }
1641 }
1642
1655 public function getrights($moduletag = '', $forcereload = 0)
1656 {
1657 $this->loadRights($moduletag, $forcereload);
1658 }
1659
1666 public function setstatus($status)
1667 {
1668 global $conf, $langs, $user;
1669
1670 $error = 0;
1671
1672 // Check parameters
1673 if (isset($this->statut)) {
1674 if ($this->statut == $status) {
1675 return 0;
1676 }
1677 } elseif (isset($this->status) && $this->status == $status) {
1678 return 0;
1679 }
1680
1681 $this->db->begin();
1682
1683 // Save in database
1684 $sql = "UPDATE ".$this->db->prefix()."user";
1685 $sql .= " SET statut = ".((int) $status);
1686 $sql .= " WHERE rowid = ".((int) $this->id);
1687 $result = $this->db->query($sql);
1688
1689 dol_syslog(get_class($this)."::setstatus", LOG_DEBUG);
1690 if ($result) {
1691 if ($status == 0) {
1692 $this->context['actionmsg'] = 'User '.$this->login.' disabled';
1693 } else {
1694 $this->context['actionmsg'] = 'User '.$this->login.' enabled';
1695 }
1696 // Call trigger
1697 $result = $this->call_trigger('USER_ENABLEDISABLE', $user);
1698 if ($result < 0) {
1699 $error++;
1700 }
1701 // End call triggers
1702 }
1703
1704 if ($error) {
1705 $this->db->rollback();
1706 return -$error;
1707 } else {
1708 $this->status = $status;
1709 $this->statut = $status;
1710 $this->db->commit();
1711 return 1;
1712 }
1713 }
1714
1722 public function setForcePasswordChange($user, $value)
1723 {
1724 $error = 0;
1725
1726 $value = (int) $value;
1727
1728 // Check parameters : no change short line
1729 if ($this->force_pass_change == $value) {
1730 return 0;
1731 }
1732
1733 $this->db->begin();
1734
1735 // Save in database
1736 $sql = "UPDATE ".$this->db->prefix()."user";
1737 $sql .= " SET force_pass_change = ".((int) $value);
1738 $sql .= " WHERE rowid = ".((int) $this->id);
1739 $result = $this->db->query($sql);
1740
1741 dol_syslog(get_class($this)."::setForcePasswordChange", LOG_DEBUG);
1742 if ($result) {
1743 $this->force_pass_change = $value;
1744 // Call trigger
1745 $result = $this->call_trigger('USER_MODIFY', $user);
1746 if ($result < 0) {
1747 $error++;
1748 }
1749 // End call triggers
1750 } else {
1751 $error++;
1752 $this->error = $this->db->lasterror();
1753 }
1754
1755 if ($error) {
1756 $this->db->rollback();
1757 return -$error;
1758 } else {
1759 $this->db->commit();
1760 return 1;
1761 }
1762 }
1763
1774 public function setCategories($categories)
1775 {
1776 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1777 return parent::setCategoriesCommon($categories, Categorie::TYPE_USER);
1778 }
1779
1786 public function delete(User $user)
1787 {
1788 $error = 0;
1789
1790 $this->db->begin();
1791
1792 $this->fetch($this->id);
1793
1794 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1795
1796 // Remove rights
1797 $sql = "DELETE FROM ".$this->db->prefix()."user_rights WHERE fk_user = ".((int) $this->id);
1798
1799 if (!$error && !$this->db->query($sql)) {
1800 $error++;
1801 $this->error = $this->db->lasterror();
1802 }
1803
1804 // Remove group
1805 $sql = "DELETE FROM ".$this->db->prefix()."usergroup_user WHERE fk_user = ".((int) $this->id);
1806 if (!$error && !$this->db->query($sql)) {
1807 $error++;
1808 $this->error = $this->db->lasterror();
1809 }
1810
1811 // Remove params
1812 $sql = "DELETE FROM ".$this->db->prefix()."user_param WHERE fk_user = ".((int) $this->id);
1813 if (!$error && !$this->db->query($sql)) {
1814 $error++;
1815 $this->error = $this->db->lasterror();
1816 }
1817
1818 // If contact, remove link
1819 if ($this->contact_id > 0) {
1820 $sql = "UPDATE ".$this->db->prefix()."socpeople SET fk_user_creat = null WHERE rowid = ".((int) $this->contact_id);
1821 if (!$error && !$this->db->query($sql)) {
1822 $error++;
1823 $this->error = $this->db->lasterror();
1824 }
1825 }
1826
1827 // Remove extrafields
1828 if (!$error) {
1829 $result = $this->deleteExtraFields();
1830 if ($result < 0) {
1831 $error++;
1832 dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1833 }
1834 }
1835
1836 // Remove user
1837 if (!$error) {
1838 $sql = "DELETE FROM ".$this->db->prefix()."user WHERE rowid = ".((int) $this->id);
1839 dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1840 if (!$this->db->query($sql)) {
1841 $error++;
1842 $this->error = $this->db->lasterror();
1843 }
1844 }
1845
1846 if (!$error) {
1847 // Call trigger
1848 $result = $this->call_trigger('USER_DELETE', $user);
1849 if ($result < 0) {
1850 $error++;
1851 $this->db->rollback();
1852 return -1;
1853 }
1854 // End call triggers
1855
1856 $this->db->commit();
1857 return 1;
1858 } else {
1859 $this->db->rollback();
1860 return -1;
1861 }
1862 }
1863
1871 public function create($user, $notrigger = 0)
1872 {
1873 global $conf, $langs;
1874 global $mysoc;
1875
1876 // Clean parameters
1877 $this->setUpperOrLowerCase();
1878
1879 $this->civility_code = trim((string) $this->civility_code);
1880 $this->login = trim((string) $this->login);
1881 $this->user_creation_id = (int) $user->id;
1882 if (!isset($this->entity)) {
1883 $this->entity = $conf->entity; // If not defined, we use default value
1884 }
1885 dol_syslog(get_class($this)."::create login=".$this->login.", user=".(is_object($user) ? $user->id : ''), LOG_DEBUG);
1886
1887 $badCharUnauthorizedIntoLoginName = getDolGlobalLoginBadCharUnauthorized();
1888
1889 // Check parameters
1890 if (getDolGlobalString('USER_MAIL_REQUIRED') && !isValidEmail($this->email)) {
1891 $langs->load("errors");
1892 $this->error = $langs->trans("ErrorBadEMail", $this->email);
1893 return -1;
1894 }
1895 if (empty($this->login)) {
1896 $langs->load("errors");
1897 $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Login"));
1898 return -1;
1899 } elseif ($badCharUnauthorizedIntoLoginName !== '' && preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) {
1900 $langs->load("errors");
1901 $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login"));
1902 return -1;
1903 }
1904
1905 $this->datec = dol_now();
1906
1907 $error = 0;
1908 $this->db->begin();
1909
1910 // Check if login already exists in same entity or into entity 0.
1911 if ($this->login) {
1912 $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)."'";
1913 $resqltochecklogin = $this->db->query($sqltochecklogin);
1914 if ($resqltochecklogin) {
1915 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
1916 if ($objtochecklogin && $objtochecklogin->nb > 0) {
1917 $langs->load("errors");
1918 $this->error = $langs->trans("ErrorLoginAlreadyExists", $this->login);
1919 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
1920 $this->db->rollback();
1921 return -6;
1922 }
1923 $this->db->free($resqltochecklogin);
1924 }
1925 }
1926 if (!empty($this->email)) {
1927 $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)."'";
1928 $resqltochecklogin = $this->db->query($sqltochecklogin);
1929 if ($resqltochecklogin) {
1930 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
1931 if ($objtochecklogin && $objtochecklogin->nb > 0) {
1932 $langs->load("errors");
1933 $this->error = $langs->trans("ErrorEmailAlreadyExists", $this->email);
1934 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
1935 $this->db->rollback();
1936 return -6;
1937 }
1938 $this->db->free($resqltochecklogin);
1939 }
1940 }
1941
1942 // Insert into database
1943 $sql = "INSERT INTO ".$this->db->prefix()."user (datec, login, ldap_sid, fk_user_creat, entity)";
1944 $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).")";
1945 $result = $this->db->query($sql);
1946
1947 dol_syslog(get_class($this)."::create", LOG_DEBUG);
1948 if ($result) {
1949 $this->id = $this->db->last_insert_id($this->db->prefix()."user");
1950
1951 // Set default rights
1952 if ($this->set_default_rights() < 0) {
1953 $this->error = 'ErrorFailedToSetDefaultRightOfUser';
1954 $this->db->rollback();
1955 return -5;
1956 }
1957
1958 if (getDolGlobalString('MAIN_DEFAULT_WAREHOUSE_USER') && getDolGlobalString('STOCK_USERSTOCK_AUTOCREATE')) {
1959 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
1960 $langs->load("stocks");
1961
1962 $entrepot = new Entrepot($this->db);
1963 $entrepot->label = $langs->trans("PersonalStock", $this->getFullName($langs));
1964 $entrepot->libelle = $entrepot->label; // For backward compatibility
1965 $entrepot->description = $langs->trans("ThisWarehouseIsPersonalStock", $this->getFullName($langs));
1966 $entrepot->statut = 1;
1967 $entrepot->country_id = $mysoc->country_id;
1968
1969 $warehouseid = $entrepot->create($user);
1970
1971 $this->fk_warehouse = $warehouseid;
1972 }
1973
1974 // Update minor fields
1975 $result = $this->update($user, 1, 1);
1976 if ($result < 0) {
1977 $this->db->rollback();
1978 return -4;
1979 }
1980
1981 if (!$notrigger) {
1982 // Call trigger
1983 $result = $this->call_trigger('USER_CREATE', $user);
1984 if ($result < 0) {
1985 $error++;
1986 }
1987 // End call triggers
1988 }
1989
1990 if (!$error) {
1991 $this->db->commit();
1992 return $this->id;
1993 } else {
1994 //$this->error=$interface->error;
1995 dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
1996 $this->db->rollback();
1997 return -3;
1998 }
1999 } else {
2000 $this->error = $this->db->lasterror();
2001 $this->db->rollback();
2002 return -2;
2003 }
2004 }
2005
2006
2007 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2016 public function create_from_contact($contact, $login = '', $password = '')
2017 {
2018 // phpcs:enable
2019 global $user;
2020
2021 $error = 0;
2022
2023 // Define parameters
2024 $this->admin = 0;
2025 $this->civility_code = $contact->civility_code;
2026 $this->lastname = $contact->lastname;
2027 $this->firstname = $contact->firstname;
2028 //$this->gender = $contact->gender; // contact has no gender
2029 $this->email = $contact->email;
2030 $this->socialnetworks = $contact->socialnetworks;
2031 $this->office_phone = $contact->phone_pro;
2032 $this->office_fax = $contact->fax;
2033 $this->user_mobile = $contact->phone_mobile;
2034 $this->address = $contact->address;
2035 $this->zip = $contact->zip;
2036 $this->town = $contact->town;
2037 $this->setUpperOrLowerCase();
2038 $this->state_id = $contact->state_id;
2039 $this->country_id = $contact->country_id;
2040 $this->employee = 0;
2041
2042 if (empty($login)) {
2043 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
2044 $login = dol_buildlogin($contact->lastname, $contact->firstname);
2045 }
2046 $this->login = $login;
2047
2048 $this->db->begin();
2049
2050 // Create user and set $this->id. Trigger is disabled because executed later.
2051 $result = $this->create($user, 1);
2052 if ($result > 0) {
2053 $sql = "UPDATE ".$this->db->prefix()."user";
2054 $sql .= " SET fk_socpeople=".((int) $contact->id);
2055 $sql .= ", civility='".$this->db->escape($contact->civility_code)."'";
2056 if ($contact->socid > 0) {
2057 $sql .= ", fk_soc=".((int) $contact->socid);
2058 }
2059 $sql .= " WHERE rowid=".((int) $this->id);
2060
2061 $resql = $this->db->query($sql);
2062
2063 dol_syslog(get_class($this)."::create_from_contact", LOG_DEBUG);
2064 if ($resql) {
2065 $this->context['createfromcontact'] = 'createfromcontact';
2066
2067 // Call trigger
2068 $result = $this->call_trigger('USER_CREATE', $user);
2069 if ($result < 0) {
2070 $error++;
2071 $this->db->rollback();
2072 return -1;
2073 }
2074 // End call triggers
2075
2076 $this->db->commit();
2077 return $this->id;
2078 } else {
2079 $this->error = $this->db->error();
2080
2081 $this->db->rollback();
2082 return -1;
2083 }
2084 } else {
2085 // $this->error already set
2086 dol_syslog(get_class($this)."::create_from_contact - 0");
2087
2088 $this->db->rollback();
2089 return $result;
2090 }
2091 }
2092
2093 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2102 public function create_from_member($member, $login = '')
2103 {
2104 // phpcs:enable
2105 global $user;
2106
2107 // Set properties on new user
2108 $this->admin = 0;
2109 $this->civility_code = $member->civility_code;
2110 $this->lastname = $member->lastname;
2111 $this->firstname = $member->firstname;
2112 $this->gender = $member->gender;
2113 $this->email = $member->email;
2114 $this->fk_member = $member->id;
2115 $this->address = $member->address;
2116 $this->zip = $member->zip;
2117 $this->town = $member->town;
2118 $this->setUpperOrLowerCase();
2119 $this->state_id = $member->state_id;
2120 $this->country_id = $member->country_id;
2121 $this->socialnetworks = $member->socialnetworks;
2122
2123 $this->pass = $member->pass;
2124 $this->pass_crypted = $member->pass_indatabase_crypted;
2125
2126 if (empty($login)) {
2127 include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
2128 $login = dol_buildlogin($member->lastname, $member->firstname);
2129 }
2130 $this->login = $login;
2131
2132 $this->db->begin();
2133
2134 // Create and set $this->id
2135 $result = $this->create($user);
2136 if ($result > 0) {
2137 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
2138 $newpass = $this->setPassword($user, $this->pass);
2139 if (is_int($newpass) && $newpass < 0) {
2140 $result = -2;
2141 }
2142 } 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.
2143 $sql = "UPDATE ".$this->db->prefix()."user";
2144 $sql .= " SET pass_crypted = '".$this->db->escape($this->pass_crypted)."'";
2145 $sql .= " WHERE rowid=".((int) $this->id);
2146
2147 $resql = $this->db->query($sql);
2148 if (!$resql) {
2149 $result = -1;
2150 }
2151 }
2152
2153 if ($result > 0 && $member->socid) { // If member is linked to a thirdparty
2154 $sql = "UPDATE ".$this->db->prefix()."user";
2155 $sql .= " SET fk_soc=".((int) $member->socid);
2156 $sql .= " WHERE rowid=".((int) $this->id);
2157
2158 dol_syslog(get_class($this)."::create_from_member", LOG_DEBUG);
2159 $resql = $this->db->query($sql);
2160 if ($resql) {
2161 $this->db->commit();
2162 return $this->id;
2163 } else {
2164 $this->error = $this->db->lasterror();
2165
2166 $this->db->rollback();
2167 return -1;
2168 }
2169 }
2170 }
2171
2172 if ($result > 0) {
2173 $this->db->commit();
2174 return $this->id;
2175 } else {
2176 // $this->error was already set
2177 $this->db->rollback();
2178 return -2;
2179 }
2180 }
2181
2182 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2188 public function set_default_rights()
2189 {
2190 // phpcs:enable
2191 global $conf;
2192
2193 $rd = array();
2194 $num = 0;
2195 $sql = "SELECT id FROM ".$this->db->prefix()."rights_def";
2196 $sql .= " WHERE bydefault = 1";
2197 $sql .= " AND entity = ".((int) $conf->entity);
2198
2199 $resql = $this->db->query($sql);
2200 if ($resql) {
2201 $num = $this->db->num_rows($resql);
2202 $i = 0;
2203 while ($i < $num) {
2204 $row = $this->db->fetch_row($resql);
2205 $rd[$i] = $row[0];
2206 $i++;
2207 }
2208 $this->db->free($resql);
2209 }
2210 $i = 0;
2211 while ($i < $num) {
2212 $sql = "DELETE FROM ".$this->db->prefix()."user_rights WHERE fk_user = ".((int) $this->id)." AND fk_id=".((int) $rd[$i]);
2213 $result = $this->db->query($sql);
2214
2215 $sql = "INSERT INTO ".$this->db->prefix()."user_rights (fk_user, fk_id) VALUES (".((int) $this->id).", ".((int) $rd[$i]).")";
2216 $result = $this->db->query($sql);
2217 if (!$result) {
2218 return -1;
2219 }
2220 $i++;
2221 }
2222
2223 return $i;
2224 }
2225
2236 public function update($user, $notrigger = 0, $nosyncmember = 0, $nosyncmemberpass = 0, $nosynccontact = 0)
2237 {
2238 global $langs;
2239
2240 if (empty($this->country_id) && !empty($this->country_code)) {
2241 $country_id = getCountry($this->country_code, '3');
2242 $this->country_id = is_int($country_id) ? $country_id : 0;
2243 }
2244
2245 $nbrowsaffected = 0;
2246 $error = 0;
2247
2248 dol_syslog(get_class($this)."::update notrigger=".$notrigger.", nosyncmember=".$nosyncmember.", nosyncmemberpass=".$nosyncmemberpass);
2249
2250 // Clean parameters
2251 $this->civility_code = trim((string) $this->civility_code);
2252 $this->lastname = trim((string) $this->lastname);
2253 $this->firstname = trim((string) $this->firstname);
2254 $this->ref_employee = trim((string) $this->ref_employee);
2255 $this->national_registration_number = trim((string) $this->national_registration_number);
2256 $this->employee = ($this->employee > 0 ? $this->employee : 0);
2257 $this->login = trim((string) $this->login);
2258 $this->gender = trim((string) $this->gender);
2259
2260 $this->pass = trim((string) $this->pass);
2261 $this->api_key = trim((string) $this->api_key);
2262 $this->datestartvalidity = empty($this->datestartvalidity) ? '' : $this->datestartvalidity;
2263 $this->dateendvalidity = empty($this->dateendvalidity) ? '' : $this->dateendvalidity;
2264
2265 $this->address = trim((string) $this->address);
2266 $this->zip = trim((string) $this->zip);
2267 $this->town = trim((string) $this->town);
2268
2269 $this->state_id = ($this->state_id > 0 ? $this->state_id : 0);
2270 $this->country_id = ($this->country_id > 0 ? $this->country_id : 0);
2271 $this->office_phone = trim((string) $this->office_phone);
2272 $this->office_fax = trim((string) $this->office_fax);
2273 $this->user_mobile = trim((string) $this->user_mobile);
2274 $this->personal_mobile = trim((string) $this->personal_mobile);
2275 $this->email = trim((string) $this->email);
2276 $this->personal_email = trim((string) $this->personal_email);
2277
2278 $this->job = trim((string) $this->job);
2279 $this->signature = trim((string) $this->signature);
2280 $this->note_public = trim((string) $this->note_public);
2281 $this->note_private = trim((string) $this->note_private);
2282 $this->openid = trim((string) $this->openid);
2283 $this->admin = ($this->admin > 0 ? $this->admin : 0);
2284 $this->user_modification_id = $user->id;
2285
2286 $this->accountancy_code_user_general = trim((string) $this->accountancy_code_user_general);
2287 $this->accountancy_code = trim((string) $this->accountancy_code);
2288 $this->color = trim(str_replace('#', '', (string) $this->color));
2289 $this->dateemployment = empty($this->dateemployment) ? '' : $this->dateemployment;
2290 $this->dateemploymentend = empty($this->dateemploymentend) ? '' : $this->dateemploymentend;
2291
2292 $this->birth = empty($this->birth) ? '' : $this->birth;
2293 $this->fk_warehouse = (int) $this->fk_warehouse;
2294 $this->fk_establishment = (int) $this->fk_establishment;
2295
2296 $this->setUpperOrLowerCase();
2297
2298 // Check parameters
2299 $badCharUnauthorizedIntoLoginName = getDolGlobalLoginBadCharUnauthorized();
2300
2301 if (getDolGlobalString('USER_MAIL_REQUIRED') && !isValidEmail($this->email)) {
2302 $langs->load("errors");
2303 $this->error = $langs->trans("ErrorBadEMail", $this->email);
2304 return -1;
2305 }
2306 if (empty($this->login)) {
2307 $langs->load("errors");
2308 $this->error = $langs->trans("ErrorFieldRequired", 'Login');
2309 return -1;
2310 } elseif ($badCharUnauthorizedIntoLoginName !== '' && preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) {
2311 $langs->load("errors");
2312 $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login"));
2313 return -1;
2314 }
2315
2316 $this->db->begin();
2317
2318 // Check if login already exists in same entity or into entity 0.
2319 if (is_object($this->oldcopy) && !$this->oldcopy->isEmpty() && $this->oldcopy->login != $this->login) {
2320 $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)."'";
2321 $resqltochecklogin = $this->db->query($sqltochecklogin);
2322 if ($resqltochecklogin) {
2323 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
2324 if ($objtochecklogin && $objtochecklogin->nb > 0) {
2325 $langs->load("errors");
2326 $this->error = $langs->trans("ErrorLoginAlreadyExists", $this->login);
2327 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
2328 $this->db->rollback();
2329 return -1;
2330 }
2331 }
2332 }
2333 if (is_object($this->oldcopy) && !$this->oldcopy->isEmpty() && !empty($this->email) && $this->oldcopy->email != $this->email) {
2334 $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)."'";
2335 $resqltochecklogin = $this->db->query($sqltochecklogin);
2336 if ($resqltochecklogin) {
2337 $objtochecklogin = $this->db->fetch_object($resqltochecklogin);
2338 if ($objtochecklogin && $objtochecklogin->nb > 0) {
2339 $langs->load("errors");
2340 $this->error = $langs->trans("ErrorEmailAlreadyExists", $this->email);
2341 dol_syslog(get_class($this)."::create ".$this->error, LOG_DEBUG);
2342 $this->db->rollback();
2343 return -1;
2344 }
2345 }
2346 }
2347
2348 // Update data
2349 $sql = "UPDATE ".$this->db->prefix()."user SET";
2350 $sql .= " civility = '".$this->db->escape($this->civility_code)."'";
2351 $sql .= ", lastname = '".$this->db->escape($this->lastname)."'";
2352 $sql .= ", firstname = '".$this->db->escape($this->firstname)."'";
2353 $sql .= ", ref_employee = '".$this->db->escape($this->ref_employee)."'";
2354 $sql .= ", national_registration_number = '".$this->db->escape($this->national_registration_number)."'";
2355 $sql .= ", employee = ".(int) $this->employee;
2356 $sql .= ", login = '".$this->db->escape($this->login)."'";
2357 $sql .= ", api_key = ".($this->api_key ? "'".$this->db->escape(dolEncrypt($this->api_key, '', '', 'dolibarr'))."'" : "null");
2358 $sql .= ", gender = ".($this->gender != -1 ? "'".$this->db->escape($this->gender)."'" : "null"); // 'man' or 'woman' or 'other'
2359 $sql .= ", birth=".(strval($this->birth) != '' ? "'".$this->db->idate($this->birth, 'tzserver')."'" : 'null');
2360 if (!empty($user->admin)) {
2361 $sql .= ", admin = ".(int) $this->admin; // admin flag can be set/unset only by an admin user
2362 }
2363 $sql .= ", address = '".$this->db->escape($this->address)."'";
2364 $sql .= ", zip = '".$this->db->escape($this->zip)."'";
2365 $sql .= ", town = '".$this->db->escape($this->town)."'";
2366 $sql .= ", fk_state = ".((!empty($this->state_id) && $this->state_id > 0) ? ((int) $this->state_id) : "null");
2367 $sql .= ", fk_country = ".((!empty($this->country_id) && $this->country_id > 0) ? ((int) $this->country_id) : "null");
2368 $sql .= ", office_phone = '".$this->db->escape($this->office_phone)."'";
2369 $sql .= ", office_fax = '".$this->db->escape($this->office_fax)."'";
2370 $sql .= ", user_mobile = '".$this->db->escape($this->user_mobile)."'";
2371 $sql .= ", personal_mobile = '".$this->db->escape($this->personal_mobile)."'";
2372 $sql .= ", email = '".$this->db->escape($this->email)."'";
2373 $sql .= ", personal_email = '".$this->db->escape($this->personal_email)."'";
2374 $sql .= ", socialnetworks = '".$this->db->escape(json_encode($this->socialnetworks))."'";
2375 $sql .= ", job = '".$this->db->escape($this->job)."'";
2376 $sql .= ", signature = '".$this->db->escape($this->signature)."'";
2377 $sql .= ", accountancy_code_user_general = '".$this->db->escape($this->accountancy_code_user_general)."'";
2378 $sql .= ", accountancy_code = '".$this->db->escape($this->accountancy_code)."'";
2379 $sql .= ", color = '".$this->db->escape($this->color)."'";
2380 $sql .= ", dateemployment=".(strval($this->dateemployment) != '' ? "'".$this->db->idate($this->dateemployment)."'" : 'null');
2381 $sql .= ", dateemploymentend=".(strval($this->dateemploymentend) != '' ? "'".$this->db->idate($this->dateemploymentend)."'" : 'null');
2382 $sql .= ", datestartvalidity=".(strval($this->datestartvalidity) != '' ? "'".$this->db->idate($this->datestartvalidity)."'" : 'null');
2383 $sql .= ", dateendvalidity=".(strval($this->dateendvalidity) != '' ? "'".$this->db->idate($this->dateendvalidity)."'" : 'null');
2384 $sql .= ", note_private = '".$this->db->escape($this->note_private)."'";
2385 $sql .= ", note_public = '".$this->db->escape($this->note_public)."'";
2386 $sql .= ", photo = ".($this->photo ? "'".$this->db->escape($this->photo)."'" : "null");
2387 $sql .= ", openid = ".($this->openid ? "'".$this->db->escape($this->openid)."'" : "null");
2388 $sql .= ", fk_user = ".($this->fk_user > 0 ? ((int) $this->fk_user) : "null");
2389 $sql .= ", fk_user_modif = ".($this->user_modification_id > 0 ? ((int) $this->user_modification_id) : "null");
2390 $sql .= ", fk_user_expense_validator = ".($this->fk_user_expense_validator > 0 ? ((int) $this->fk_user_expense_validator) : "null");
2391 $sql .= ", fk_user_holiday_validator = ".($this->fk_user_holiday_validator > 0 ? ((int) $this->fk_user_holiday_validator) : "null");
2392 if (isset($this->thm) || $this->thm != '') {
2393 $sql .= ", thm= ".($this->thm != '' ? "'".$this->db->escape($this->thm)."'" : "null");
2394 }
2395 if (isset($this->tjm) || $this->tjm != '') {
2396 $sql .= ", tjm= ".($this->tjm != '' ? "'".$this->db->escape($this->tjm)."'" : "null");
2397 }
2398 if (isset($this->salary) || $this->salary != '') {
2399 $sql .= ", salary= ".($this->salary != '' ? "'".$this->db->escape($this->salary)."'" : "null");
2400 }
2401 if (isset($this->salaryextra) || $this->salaryextra != '') {
2402 $sql .= ", salaryextra= ".($this->salaryextra != '' ? "'".$this->db->escape($this->salaryextra)."'" : "null");
2403 }
2404 $sql .= ", weeklyhours= ".($this->weeklyhours != '' ? "'".$this->db->escape($this->weeklyhours)."'" : "null");
2405 if (!empty($user->admin) && empty($user->entity) && $user->id != $this->id) {
2406 $sql .= ", entity = ".((int) $this->entity); // entity flag can be set/unset only by an another superadmin user
2407 }
2408
2409 $sql .= ", default_range = ".($this->default_range > 0 ? ((int) $this->default_range) : 'null');
2410 $sql .= ", default_c_exp_tax_cat = ".($this->default_c_exp_tax_cat > 0 ? ((int) $this->default_c_exp_tax_cat) : 'null');
2411 $sql .= ", fk_warehouse = ".($this->fk_warehouse > 0 ? ((int) $this->fk_warehouse) : "null");
2412 $sql .= ", fk_establishment = ".($this->fk_establishment > 0 ? ((int) $this->fk_establishment) : "null");
2413 $sql .= ", lang = ".($this->lang ? "'".$this->db->escape($this->lang)."'" : "null");
2414 $sql .= ", force_pass_change = ".($this->force_pass_change ? ((int) $this->force_pass_change) : "0");
2415 $sql .= " WHERE rowid = ".((int) $this->id);
2416
2417 dol_syslog(get_class($this)."::update", LOG_DEBUG);
2418 $resql = $this->db->query($sql);
2419 if ($resql) {
2420 $nbrowsaffected += $this->db->affected_rows($resql);
2421
2422 // Update password
2423 if (!empty($this->pass)) {
2424 if ($this->pass != $this->pass_indatabase && !dol_verifyHash($this->pass, $this->pass_indatabase_crypted)) {
2425 // If a new value for password is set and different than the one encrypted into database
2426 $result = $this->setPassword($user, $this->pass, 0, $notrigger, $nosyncmemberpass, 0, 1);
2427 if (is_int($result) && $result < 0) {
2428 return -5;
2429 }
2430 }
2431 }
2432
2433 // If user is linked to a member, remove old link to this member
2434 if ($this->fk_member > 0) {
2435 dol_syslog(get_class($this)."::update remove link with member. We will recreate it later", LOG_DEBUG);
2436 $sql = "UPDATE ".$this->db->prefix()."user SET fk_member = NULL where fk_member = ".((int) $this->fk_member);
2437 $resql = $this->db->query($sql);
2438 if (!$resql) {
2439 $this->error = $this->db->error();
2440 $this->db->rollback();
2441 return -5;
2442 }
2443 }
2444 // Set link to user
2445 dol_syslog(get_class($this)."::update set link with member", LOG_DEBUG);
2446 $sql = "UPDATE ".$this->db->prefix()."user SET fk_member =".($this->fk_member > 0 ? ((int) $this->fk_member) : 'null')." where rowid = ".((int) $this->id);
2447 $resql = $this->db->query($sql);
2448 if (!$resql) {
2449 $this->error = $this->db->error();
2450 $this->db->rollback();
2451 return -5;
2452 }
2453
2454 if ($nbrowsaffected) { // If something has changed in data
2455 if ($this->fk_member > 0 && !$nosyncmember) {
2456 dol_syslog(get_class($this)."::update user is linked with a member. We try to update member too.", LOG_DEBUG);
2457
2458 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
2459
2460 // This user is linked with a member, so we also update member information
2461 // if this is an update.
2462 $adh = new Adherent($this->db);
2463 $result = $adh->fetch($this->fk_member);
2464
2465 if ($result > 0) {
2466 $adh->civility_code = $this->civility_code;
2467 $adh->firstname = $this->firstname;
2468 $adh->lastname = $this->lastname;
2469 $adh->login = $this->login;
2470 $adh->gender = $this->gender;
2471 $adh->birth = $this->birth;
2472
2473 $adh->pass = $this->pass;
2474
2475 $adh->address = $this->address;
2476 $adh->town = $this->town;
2477 $adh->zip = $this->zip;
2478 $adh->state_id = $this->state_id;
2479 $adh->country_id = $this->country_id;
2480
2481 $adh->email = $this->email;
2482
2483 $adh->socialnetworks = $this->socialnetworks;
2484
2485 $adh->phone = $this->office_phone;
2486 $adh->phone_mobile = $this->user_mobile;
2487
2488 $adh->default_lang = $this->lang;
2489
2490 $adh->user_id = $this->id;
2491 $adh->user_login = $this->login;
2492
2493 $result = $adh->update($user, 0, 1, 0);
2494 if ($result < 0) {
2495 $this->error = $adh->error;
2496 $this->errors = $adh->errors;
2497 dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
2498 $error++;
2499 }
2500 } elseif ($result < 0) {
2501 $this->error = $adh->error;
2502 $this->errors = $adh->errors;
2503 $error++;
2504 }
2505 }
2506
2507 if ($this->contact_id > 0 && !$nosynccontact) {
2508 dol_syslog(get_class($this)."::update user is linked with a contact. We try to update contact too.", LOG_DEBUG);
2509
2510 require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
2511
2512 // This user is linked with a contact, so we also update contact information if this is an update.
2513 $tmpobj = new Contact($this->db);
2514 $result = $tmpobj->fetch($this->contact_id);
2515
2516 if ($result >= 0) {
2517 $tmpobj->civility_code = $this->civility_code;
2518 $tmpobj->firstname = $this->firstname;
2519 $tmpobj->lastname = $this->lastname;
2520 $tmpobj->login = $this->login;
2521 $tmpobj->gender = $this->gender;
2522 $tmpobj->birth = $this->birth;
2523
2524 //$tmpobj->pass=$this->pass;
2525
2526 $tmpobj->email = $this->email;
2527
2528 $tmpobj->socialnetworks = $this->socialnetworks;
2529
2530 $tmpobj->phone_pro = $this->office_phone;
2531 $tmpobj->phone_mobile = $this->user_mobile;
2532 $tmpobj->fax = $this->office_fax;
2533
2534 $tmpobj->default_lang = $this->lang;
2535
2536 $tmpobj->address = $this->address;
2537 $tmpobj->town = $this->town;
2538 $tmpobj->zip = $this->zip;
2539 $tmpobj->state_id = $this->state_id;
2540 $tmpobj->country_id = $this->country_id;
2541
2542 $tmpobj->user_id = $this->id;
2543 $tmpobj->user_login = $this->login;
2544
2545 $result = $tmpobj->update($tmpobj->id, $user, 0, 'update', 1);
2546 if ($result < 0) {
2547 $this->error = $tmpobj->error;
2548 $this->errors = $tmpobj->errors;
2549 dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
2550 $error++;
2551 }
2552 } else {
2553 $this->error = $tmpobj->error;
2554 $this->errors = $tmpobj->errors;
2555 $error++;
2556 }
2557 }
2558 }
2559
2560 $action = 'update';
2561
2562 // Actions on extra fields
2563 if (!$error) {
2564 $result = $this->insertExtraFields();
2565 if ($result < 0) {
2566 $error++;
2567 }
2568 }
2569
2570 if (!$error && !$notrigger) {
2571 // Call trigger
2572 $result = $this->call_trigger('USER_MODIFY', $user);
2573 if ($result < 0) {
2574 $error++;
2575 }
2576 // End call triggers
2577 }
2578
2579 if (!$error) {
2580 $this->db->commit();
2581 return $nbrowsaffected;
2582 } else {
2583 dol_syslog(get_class($this)."::update error=".$this->error, LOG_ERR);
2584 $this->db->rollback();
2585 return -1;
2586 }
2587 } else {
2588 $this->error = $this->db->lasterror();
2589 $this->db->rollback();
2590 return -2;
2591 }
2592 }
2593
2594 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2601 public function update_last_login_date()
2602 {
2603 // phpcs:enable
2604 $now = dol_now();
2605
2606 $userremoteip = getUserRemoteIP();
2607
2608 $sql = "UPDATE ".$this->db->prefix()."user SET";
2609 $sql .= " datepreviouslogin = datelastlogin,";
2610 $sql .= " ippreviouslogin = iplastlogin,";
2611 $sql .= " datelastlogin = '".$this->db->idate($now)."',";
2612 $sql .= " iplastlogin = '".$this->db->escape($userremoteip)."',";
2613 $sql .= " tms = tms"; // The last update date must change because the last login date is updated
2614 $sql .= " WHERE rowid = ".((int) $this->id);
2615
2616 dol_syslog(get_class($this)."::update_last_login_date user->id=".$this->id." ".$sql, LOG_DEBUG);
2617 $resql = $this->db->query($sql);
2618 if ($resql) {
2619 $this->datepreviouslogin = $this->datelastlogin;
2620 $this->datelastlogin = $now;
2621 $this->ippreviouslogin = $this->iplastlogin;
2622 $this->iplastlogin = $userremoteip;
2623 return 1;
2624 } else {
2625 $this->error = $this->db->lasterror().' sql='.$sql;
2626 return -1;
2627 }
2628 }
2629
2630
2643 public function setPassword($user, $password = '', $changelater = 0, $notrigger = 0, $nosyncmember = 0, $passwordalreadycrypted = 0, $flagdelsessionsbefore = 1)
2644 {
2645 global $conf, $langs;
2646 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
2647
2648 $error = 0;
2649
2650 dol_syslog(get_class($this)."::setPassword user=".$user->id." password=".preg_replace('/./i', '*', $password)." changelater=".$changelater." notrigger=".$notrigger." nosyncmember=".$nosyncmember, LOG_DEBUG);
2651
2652 // If new password not provided, we generate one
2653 if (!$password) {
2654 $password = getRandomPassword(false);
2655 $passwordalreadycrypted = 0; // Just generated, so not crypted
2656 }
2657
2658 // Check and encrypt the password
2659 if (!empty($passwordalreadycrypted)) {
2660 $password_crypted = $password; // Reuse crypted password
2661 } else {
2662 if (getDolGlobalString('USER_PASSWORD_GENERATED')) {
2663 // Add a check on rules for password syntax using the setup of the password generator
2664 require_once DOL_DOCUMENT_ROOT.'/core/modules/security/generate/modules_genpassword.php';
2665 $modGeneratePass = ModeleGenPassword::loadAndInstantiate(getDolGlobalString('USER_PASSWORD_GENERATED'), $this->db, $conf, $langs, $user);
2666 if ($modGeneratePass) {
2667 '@phan-var-force ModeleGenPassword $modGeneratePass';
2668
2669 // To check an input user password, we disable the cleaning on ambiguous characters (this is used only for auto-generated password)
2670 $modGeneratePass->WithoutAmbi = 0;
2671
2672 // Call to validatePassword($password) to check pass match rules
2673 $testpassword = $modGeneratePass->validatePassword($password);
2674 if (!$testpassword) {
2675 $this->error = $modGeneratePass->error;
2676 return -1;
2677 }
2678 }
2679 }
2680
2681
2682 // Now, we encrypt the new password
2683 $password_crypted = (string) dol_hash($password);
2684 }
2685
2686 // Update password
2687 if (!$changelater) {
2688 if (!is_object($this->oldcopy)) {
2689 $this->oldcopy = clone $this;
2690 }
2691
2692 $now = dol_now();
2693
2694 $this->db->begin();
2695
2696 $sql = "UPDATE ".$this->db->prefix()."user";
2697 $sql .= " SET pass_crypted = '".$this->db->escape($password_crypted)."',";
2698 $sql .= " datelastpassvalidation = '".$this->db->idate(dol_now())."',";
2699 $sql .= " pass_temp = null,";
2700 $sql .= " force_pass_change = 0";
2701 if (!empty($flagdelsessionsbefore)) {
2702 $sql .= ", flagdelsessionsbefore = '".$this->db->idate($now - 5, 'gmt')."'";
2703 }
2704 if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
2705 $sql .= ", pass = null";
2706 } else {
2707 $sql .= ", pass = '".$this->db->escape($password)."'";
2708 }
2709 $sql .= " WHERE rowid = ".((int) $this->id);
2710
2711 dol_syslog(get_class($this)."::setPassword", LOG_DEBUG);
2712
2713 $result = $this->db->query($sql);
2714 if ($result) {
2715 if ($this->db->affected_rows($result)) {
2716 $this->pass = $password;
2717 $this->pass_indatabase = $password;
2718 $this->pass_indatabase_crypted = (string) $password_crypted;
2719 $this->force_pass_change = 0;
2720
2721 if ($this->fk_member && !$nosyncmember) {
2722 require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
2723
2724 // This user is linked with a member, so we also update members information
2725 // if this is an update.
2726 $adh = new Adherent($this->db);
2727 $result = $adh->fetch($this->fk_member);
2728
2729 if ($result >= 0) {
2730 $result = $adh->setPassword($user, $this->pass, (!getDolGlobalString('DATABASE_PWD_ENCRYPTED') ? 0 : 1), 1); // The encryption is not managed in the 'adherent' module
2731 if (is_int($result) && $result < 0) {
2732 $this->error = $adh->error;
2733 dol_syslog(get_class($this)."::setPassword ".$this->error, LOG_ERR);
2734 $error++;
2735 }
2736 } else {
2737 $this->error = $adh->error;
2738 $error++;
2739 }
2740 }
2741
2742 dol_syslog(get_class($this)."::setPassword notrigger=".$notrigger." error=".$error, LOG_DEBUG);
2743
2744 // Call trigger for the "security events" log
2745 $user->context['audit'] = 'login='.$user->login;
2746 if (!empty($flagdelsessionsbefore)) {
2747 $user->context['audit'] .= " - flagdelsessionsbefore set to '".$this->db->idate($now - 5, 'gmt')."'";
2748 }
2749
2750 if (!$error && !$notrigger) {
2751 // Call trigger
2752 $result = $this->call_trigger('USER_NEW_PASSWORD', $user);
2753 if ($result < 0) {
2754 $error++;
2755 $this->db->rollback();
2756 return -1;
2757 }
2758 // End call triggers
2759 }
2760
2761 $this->db->commit();
2762 return $this->pass;
2763 } else {
2764 $this->db->rollback();
2765 return 0;
2766 }
2767 } else {
2768 $this->db->rollback();
2769 dol_print_error($this->db);
2770 return -1;
2771 }
2772 } else {
2773 // We store password in password temporary field.
2774 // After receiving confirmation link, we will erase and store it in pass_crypted
2775 $sql = "UPDATE ".$this->db->prefix()."user";
2776 $sql .= " SET pass_temp = '".$this->db->escape($password)."'";
2777 $sql .= " WHERE rowid = ".((int) $this->id);
2778
2779 dol_syslog(get_class($this)."::setPassword", LOG_DEBUG); // No log
2780 $result = $this->db->query($sql);
2781 if ($result) {
2782 return $password;
2783 } else {
2784 dol_print_error($this->db);
2785 return -3;
2786 }
2787 }
2788 }
2789
2790 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2799 public function send_password($user, $password = '', $changelater = 0)
2800 {
2801 // phpcs:enable
2802 global $conf, $langs;
2804
2805 require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2806
2807 $msgishtml = 0;
2808
2809 // Define $msg
2810 $mesg = '';
2811
2812 $outputlangs = new Translate("", $conf);
2813
2814 if (getDolGlobalString('MAIN_LANG_DEFAULT')) {
2815 $outputlangs->setDefaultLang(getDolGlobalString('MAIN_LANG_DEFAULT'));
2816 } else { // If user has not defined its own language, we used current language
2817 $outputlangs = $langs;
2818 }
2819
2820 // Load translation files required by the page
2821 $outputlangs->loadLangs(array("main", "errors", "users", "other"));
2822
2823 $appli = getDolGlobalString('MAIN_APPLICATION_TITLE', constant('DOL_APPLICATION_TITLE'));
2824
2825 $subject = '['.$appli.'] '.$outputlangs->transnoentitiesnoconv("SubjectNewPassword", $appli);
2826
2827 // Define $urlwithroot
2828 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2829 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
2830
2831 if (!$changelater) {
2832 $url = $urlwithroot.'/';
2833 if (getDolGlobalString('URL_REDIRECTION_AFTER_CHANGEPASSWORD')) {
2834 $url = getDolGlobalString('URL_REDIRECTION_AFTER_CHANGEPASSWORD');
2835 }
2836
2837 dol_syslog(get_class($this)."::send_password changelater is off, url=".$url);
2838
2839 $mesg .= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived")."\n";
2840 $mesg .= $outputlangs->transnoentitiesnoconv("NewKeyIs")." :\n\n";
2841 $mesg .= $outputlangs->transnoentitiesnoconv("Login")." = ".$this->login."\n";
2842 $mesg .= $outputlangs->transnoentitiesnoconv("Password")." = ".$password."\n\n";
2843 $mesg .= "\n";
2844
2845 $mesg .= $outputlangs->transnoentitiesnoconv("ClickHereToGoTo", $appli).': '.$url."\n\n";
2846 $mesg .= "--\n";
2847 $mesg .= $user->getFullName($outputlangs); // Username that send the email (not the user for who we want to reset password)
2848 } else {
2849 //print $password.'-'.$this->id.'-'.$conf->file->instance_unique_id;
2850 $url = $urlwithroot.'/user/passwordforgotten.php?action=validatenewpassword';
2851 $url .= '&username='.urlencode($this->login)."&passworduidhash=".urlencode(dol_hash($password.'-'.$this->id.'-'.$conf->file->instance_unique_id));
2852 if (isModEnabled('multicompany')) {
2853 $url .= '&entity='.(!empty($this->entity) ? $this->entity : 1);
2854 }
2855
2856 dol_syslog(get_class($this)."::send_password changelater is on, url=".$url);
2857
2858 $msgishtml = 1;
2859
2860 $mesg .= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived")."<br>\n";
2861 $mesg .= $outputlangs->transnoentitiesnoconv("NewKeyWillBe")." :<br>\n<br>\n";
2862 $mesg .= '<strong>'.$outputlangs->transnoentitiesnoconv("Login")."</strong> = ".$this->login."<br>\n";
2863 $mesg .= '<strong>'.$outputlangs->transnoentitiesnoconv("Password")."</strong> = ".$password."<br>\n<br>\n";
2864 $mesg .= "<br>\n";
2865 $mesg .= $outputlangs->transnoentitiesnoconv("YouMustClickToChange")." :<br>\n";
2866 $mesg .= '<a href="'.$url.'" rel="noopener">'.$outputlangs->transnoentitiesnoconv("ConfirmPasswordChange").'</a>'."<br>\n<br>\n";
2867 $mesg .= $outputlangs->transnoentitiesnoconv("ForgetIfNothing")."<br>\n<br>\n";
2868 }
2869
2870 $trackid = 'use'.$this->id;
2871 $sendcontext = 'passwordreset';
2872
2873 $mailfile = new CMailFile(
2874 $subject,
2875 $this->email,
2876 getDolGlobalString("MAIN_MAIL_EMAIL_FROM_PASSWORDRESET", getDolGlobalString("MAIN_MAIL_EMAIL_FROM")),
2877 $mesg,
2878 array(),
2879 array(),
2880 array(),
2881 '',
2882 '',
2883 0,
2884 $msgishtml,
2885 '',
2886 '',
2887 $trackid,
2888 '',
2889 $sendcontext
2890 );
2891
2892 if ($mailfile->sendfile()) {
2893 return 1;
2894 } else {
2895 $langs->trans("errors");
2896 $this->error = $langs->trans("ErrorFailedToSendPassword").' '.$mailfile->error;
2897 return -1;
2898 }
2899 }
2900
2906 public function error()
2907 {
2908 return $this->error;
2909 }
2910
2911
2912 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2918 public function fetch_clicktodial()
2919 {
2920 // phpcs:enable
2921 $sql = "SELECT url, login, pass, poste ";
2922 $sql .= " FROM ".$this->db->prefix()."user_clicktodial as u";
2923 $sql .= " WHERE u.fk_user = ".((int) $this->id);
2924
2925 $resql = $this->db->query($sql);
2926 if ($resql) {
2927 if ($this->db->num_rows($resql)) {
2928 $obj = $this->db->fetch_object($resql);
2929
2930 $this->clicktodial_url = $obj->url;
2931 $this->clicktodial_login = $obj->login;
2932 $this->clicktodial_password = $obj->pass;
2933 $this->clicktodial_poste = $obj->poste;
2934 }
2935
2936 $this->clicktodial_loaded = 1; // Data loaded (found or not)
2937
2938 $this->db->free($resql);
2939 return 1;
2940 } else {
2941 $this->error = $this->db->error();
2942 return -1;
2943 }
2944 }
2945
2946 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2952 public function update_clicktodial()
2953 {
2954 // phpcs:enable
2955 $this->db->begin();
2956
2957 $sql = "DELETE FROM ".$this->db->prefix()."user_clicktodial";
2958 $sql .= " WHERE fk_user = ".((int) $this->id);
2959
2960 dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2961
2962 $result = $this->db->query($sql);
2963
2964 $sql = "INSERT INTO ".$this->db->prefix()."user_clicktodial";
2965 $sql .= " (fk_user,url,login,pass,poste)";
2966 $sql .= " VALUES (".((int) $this->id);
2967 $sql .= ", '".$this->db->escape($this->clicktodial_url)."'";
2968 $sql .= ", '".$this->db->escape($this->clicktodial_login)."'";
2969 $sql .= ", '".$this->db->escape($this->clicktodial_password)."'";
2970 $sql .= ", '".$this->db->escape($this->clicktodial_poste)."')";
2971
2972 dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2973
2974 $result = $this->db->query($sql);
2975 if ($result) {
2976 $this->db->commit();
2977 return 1;
2978 } else {
2979 $this->db->rollback();
2980 $this->error = $this->db->lasterror();
2981 return -1;
2982 }
2983 }
2984
2985
2986 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2995 public function SetInGroup($group, $entity, $notrigger = 0)
2996 {
2997 // phpcs:enable
2998 global $langs, $user;
2999
3000 $error = 0;
3001
3002 $this->db->begin();
3003
3004 $sql = "DELETE FROM ".$this->db->prefix()."usergroup_user";
3005 $sql .= " WHERE fk_user = ".((int) $this->id);
3006 $sql .= " AND fk_usergroup = ".((int) $group);
3007 $sql .= " AND entity = ".((int) $entity);
3008
3009 $result = $this->db->query($sql);
3010
3011 $sql = "INSERT INTO ".$this->db->prefix()."usergroup_user (entity, fk_user, fk_usergroup)";
3012 $sql .= " VALUES (".((int) $entity).",".((int) $this->id).",".((int) $group).")";
3013
3014 $result = $this->db->query($sql);
3015 if ($result) {
3016 if (!$error && !$notrigger) {
3017 $this->context = array('audit' => $langs->trans("UserSetInGroup"), 'newgroupid' => $group);
3018
3019 // Call trigger
3020 $result = $this->call_trigger('USER_MODIFY', $user);
3021 if ($result < 0) {
3022 $error++;
3023 }
3024 // End call triggers
3025 }
3026
3027 if (!$error) {
3028 $this->db->commit();
3029 return 1;
3030 } else {
3031 dol_syslog(get_class($this)."::SetInGroup ".$this->error, LOG_ERR);
3032 $this->db->rollback();
3033 return -2;
3034 }
3035 } else {
3036 $this->error = $this->db->lasterror();
3037 $this->db->rollback();
3038 return -1;
3039 }
3040 }
3041
3042 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3051 public function RemoveFromGroup($group, $entity, $notrigger = 0)
3052 {
3053 // phpcs:enable
3054 global $langs, $user;
3055
3056 $error = 0;
3057
3058 $this->db->begin();
3059
3060 $sql = "DELETE FROM ".$this->db->prefix()."usergroup_user";
3061 $sql .= " WHERE fk_user = ".((int) $this->id);
3062 $sql .= " AND fk_usergroup = ".((int) $group);
3063 if (empty($entity)) {
3064 $sql .= " AND entity IN (0, 1)"; // group may be in entity 0 (so $entity=0) and link with user into entity 1.
3065 } else {
3066 $sql .= " AND entity = ".((int) $entity);
3067 }
3068
3069 $result = $this->db->query($sql);
3070 if ($result) {
3071 if (!$error && !$notrigger) {
3072 $this->context = array('audit' => $langs->trans("UserRemovedFromGroup"), 'oldgroupid' => $group);
3073
3074 // Call trigger
3075 $result = $this->call_trigger('USER_MODIFY', $user);
3076 if ($result < 0) {
3077 $error++;
3078 }
3079 // End call triggers
3080 }
3081
3082 if (!$error) {
3083 $this->db->commit();
3084 return 1;
3085 } else {
3086 dol_syslog(get_class($this)."::RemoveFromGroup ".$this->error, LOG_ERR);
3087 $this->db->rollback();
3088 return -2;
3089 }
3090 } else {
3091 $this->error = $this->db->lasterror();
3092 $this->db->rollback();
3093 return -1;
3094 }
3095 }
3096
3097
3105 {
3106 include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
3107
3108 $now = dol_now();
3109
3110 //dol_syslog("isNotIntoValidityDateRange ".$this->datestartvalidity);
3111
3112 // Check date start validity
3113 if ($this->datestartvalidity && $this->datestartvalidity > dol_get_last_hour($now)) {
3114 return 1;
3115 }
3116 // Check date end validity
3117 if ($this->dateendvalidity && $this->dateendvalidity < dol_get_first_hour($now)) {
3118 return 1;
3119 }
3120
3121 return 0;
3122 }
3123
3124
3136 public function getPhotoUrl($width, $height, $cssclass = '', $imagesize = '')
3137 {
3138 $result = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
3139 $result .= Form::showphoto('userphoto', $this, $width, $height, 0, $cssclass, $imagesize);
3140 $result .= '</a>';
3141
3142 return $result;
3143 }
3144
3151 public function getTooltipContentArray($params)
3152 {
3153 global $conf, $langs, $menumanager;
3154 global $dolibarr_main_demo;
3155
3156 $infologin = $params['infologin'] ?? 0;
3157 $option = $params['option'] ?? '';
3158
3159 $data = [];
3160 if (!empty($this->photo)) {
3161 $photo = '<div class="photointooltip floatright">';
3162 $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
3163 $photo .= '</div>';
3164 $data['photo'] = $photo;
3165 //$label .= '<div style="clear: both;"></div>';
3166 }
3167
3168 // Info Login
3169 $data['opendiv'] = '<div class="centpercent divtooltip">';
3170 $data['picto'] = img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("User").'</u> '.$this->getLibStatut(4);
3171 $data['name'] = '<br><b>'.$langs->trans('Name').':</b> '.dol_string_nohtmltag($this->getFullName($langs));
3172 if (!empty($this->login)) {
3173 $data['login'] = '<br><b>'.$langs->trans('Login').':</b> '.dol_string_nohtmltag($this->login);
3174 }
3175 if (!empty($this->job)) {
3176 $data['job'] = '<br><b>'.$langs->trans("Job").':</b> '.dol_string_nohtmltag($this->job);
3177 }
3178 $data['email'] = '<br><b>'.$langs->trans("Email").':</b> '.dol_string_nohtmltag($this->email);
3179 if (!empty($this->office_phone) || !empty($this->office_fax) || !empty($this->fax)) {
3180 $phonelist = array();
3181 if ($this->office_phone) {
3182 $phonelist[] = dol_print_phone($this->office_phone, $this->country_code, $this->id, 0, '', '&nbsp', 'phone');
3183 }
3184 if ($this->office_fax) {
3185 $phonelist[] = dol_print_phone($this->office_fax, $this->country_code, $this->id, 0, '', '&nbsp', 'fax');
3186 }
3187 if ($this->user_mobile) {
3188 $phonelist[] = dol_print_phone($this->user_mobile, $this->country_code, $this->id, 0, '', '&nbsp', 'mobile');
3189 }
3190 $data['phones'] = '<br><b>'.$langs->trans('Phone').':</b> '.implode('&nbsp;', $phonelist);
3191 }
3192 if (!empty($this->admin)) {
3193 $data['administrator'] = '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($this->admin);
3194 }
3195 if (!empty($this->accountancy_code) || $option == 'accountancy') {
3196 $langs->load("companies");
3197 $data['accountancycode'] = '<br><b>'.$langs->trans("AccountancyCode").'</b>: '.$this->accountancy_code;
3198 }
3199 $company = '';
3200 if (!empty($this->socid)) { // Add thirdparty for external users
3201 $thirdpartystatic = new Societe($this->db);
3202 $thirdpartystatic->fetch($this->socid);
3203 $companyimg = '';
3204 if (empty($params['hidethirdpartylogo'])) {
3205 $companyimg = ' '.$thirdpartystatic->getNomUrl(2, 'nolink', 0, 1); // picto only of company
3206 }
3207 $company = ' ('.$langs->trans("Company").': '.($companyimg ? $companyimg : img_picto('', 'company')).' '.dol_string_nohtmltag($thirdpartystatic->name).')';
3208 }
3209 $type = ($this->socid ? $langs->trans("ExternalUser").$company : $langs->trans("InternalUser"));
3210 $data['type'] = '<br><b>'.$langs->trans("Type").':</b> '.$type;
3211 $data['closediv'] = '</div>';
3212
3213 if ($infologin > 0) {
3214 $data['newlinelogin'] = '<br>';
3215 $data['session'] = '<br><u>'.$langs->trans("Session").'</u>';
3216 $data['ip'] = '<br><b>'.$langs->trans("IPAddress").'</b>: '.dol_string_nohtmltag(getUserRemoteIP());
3217 if (getDolGlobalString('MAIN_MODULE_MULTICOMPANY')) {
3218 $data['multicompany'] = '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (User entity '.$this->entity.')';
3219 }
3220 $data['authentication'] = '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.dol_string_nohtmltag($_SESSION["dol_authmode"].(empty($dolibarr_main_demo) ? '' : ' (demo)'));
3221 $data['connectedsince'] = '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($this->datelastlogin, "dayhour", 'tzuser');
3222 $data['previousconnexion'] = '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($this->datepreviouslogin, "dayhour", 'tzuser');
3223 $data['currenttheme'] = '<br><b>'.$langs->trans("CurrentTheme").':</b> '.dol_string_nohtmltag($conf->theme);
3224 // @phan-suppress-next-line PhanRedefinedClassReference
3225 $data['currentmenumanager'] = '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.dol_string_nohtmltag($menumanager->name);
3226 $s = picto_from_langcode($langs->getDefaultLang());
3227 $data['currentuserlang'] = '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.dol_string_nohtmltag(($s ? $s.' ' : '').$langs->getDefaultLang());
3228 $data['browser'] = '<br><b>'.$langs->trans("Browser").':</b> '.dol_string_nohtmltag($conf->browser->name.($conf->browser->version ? ' '.$conf->browser->version : '').' ('.$_SERVER['HTTP_USER_AGENT'].')');
3229 $data['layout'] = '<br><b>'.$langs->trans("Layout").':</b> '.dol_string_nohtmltag($conf->browser->layout);
3230 $data['screen'] = '<br><b>'.$langs->trans("Screen").':</b> '.dol_string_nohtmltag($_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight']);
3231 if ($conf->browser->layout == 'phone') {
3232 $data['phone'] = '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
3233 }
3234 if (!empty($_SESSION["disablemodules"])) {
3235 $data['disabledmodules'] = '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.dol_string_nohtmltag(implode(', ', explode(',', $_SESSION["disablemodules"])));
3236 }
3237 }
3238
3239 return $data;
3240 }
3241
3257 public function getNomUrl($withpictoimg = 0, $option = '', $infologin = 0, $notooltip = 0, $maxlen = 24, $hidethirdpartylogo = 0, $mode = '', $morecss = '', $save_lastsearch_value = -1)
3258 {
3259 global $langs, $hookmanager, $user;
3260
3261 if (!$user->hasRight('user', 'user', 'read') && $user->id != $this->id) {
3262 $option = 'nolink';
3263 }
3264
3265 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER') && $withpictoimg) {
3266 $withpictoimg = 0;
3267 }
3268
3269 $result = '';
3270 $params = [
3271 'id' => $this->id,
3272 'objecttype' => $this->element,
3273 'infologin' => $infologin,
3274 'option' => $option,
3275 'hidethirdpartylogo' => $hidethirdpartylogo,
3276 ];
3277 $classfortooltip = 'classfortooltip';
3278 $dataparams = '';
3279 if (getDolGlobalInt('MAIN_ENABLE_AJAX_TOOLTIP')) {
3280 $classfortooltip = 'classforajaxtooltip';
3281 $dataparams = ' data-params="'.dol_escape_htmltag(json_encode($params)).'"';
3282 $label = '';
3283 } else {
3284 $label = implode($this->getTooltipContentArray($params));
3285 }
3286
3287 $companylink = '';
3288 if (!empty($this->socid)) { // Add thirdparty for external users
3289 $thirdpartystatic = new Societe($this->db);
3290 $thirdpartystatic->fetch($this->socid);
3291 if (empty($hidethirdpartylogo)) {
3292 $companylink = ' '.$thirdpartystatic->getNomUrl(2, 'nolink', 0, 1); // picto only of company
3293 }
3294 }
3295
3296 if ($infologin < 0) {
3297 $label = '';
3298 }
3299
3300 $baseurl = DOL_URL_ROOT . '/user/card.php';
3301 if ($option == 'leave') {
3302 $baseurl = DOL_URL_ROOT . '/holiday/list.php';
3303 }
3304 $query = ['id' => $this->id];
3305 if ($option != 'nolink') {
3306 // Add param to save lastsearch_values or not
3307 $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
3308 if ($save_lastsearch_value == -1 && isset($_SERVER["PHP_SELF"]) && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
3309 $add_save_lastsearch_values = 1;
3310 }
3311 if ($add_save_lastsearch_values) {
3312 $query = array_merge($query, ['save_lastsearch_values' => 1]);
3313 }
3314 }
3315 $url = dolBuildUrl($baseurl, $query);
3316
3317 $linkstart = '<a href="'.$url.'"';
3318 $linkclose = "";
3319 if (empty($notooltip)) {
3320 if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3321 $langs->load("users");
3322 $label = $langs->trans("ShowUser");
3323 $linkclose .= ' alt="'.dolPrintHTMLForAttribute($label).'"';
3324 }
3325 $linkclose .= ($label ? ' title="'.dolPrintHTMLForAttribute($label).'"' : ' title="tocomplete"');
3326 $linkclose .= $dataparams . ' class="'.$classfortooltip.($morecss ? ' '.$morecss : '').'"';
3327 } else {
3328 $linkclose = ($morecss ? ' class="'.$morecss.'"' : '');
3329 }
3330
3331 $linkstart .= $linkclose.'>';
3332 $linkend = '</a>';
3333
3334 //if ($withpictoimg == -1) $result.='<div class="nowrap">';
3335 $result .= (($option == 'nolink') ? '' : $linkstart);
3336 if ($withpictoimg) {
3337 $paddafterimage = '';
3338 if (abs((int) $withpictoimg) == 1 || abs((int) $withpictoimg) == 4) {
3339 $paddafterimage = 'style="margin-'.($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right').': 3px;"';
3340 }
3341 // Only picto
3342 if ($withpictoimg > 0) {
3343 $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>';
3344 } else {
3345 // Picto must be a photo
3346 $picto = '<!-- picto photo user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'"'.($paddafterimage ? ' '.$paddafterimage : '').'>';
3347 $picto .= Form::showphoto('userphoto', $this, 0, 0, 0, 'userphoto'.(($withpictoimg == -3 || $withpictoimg == -4) ? 'small' : ''), 'mini', 0, 1);
3348 $picto .= '</span>';
3349 }
3350 $result .= $picto;
3351 }
3352
3353 if ($withpictoimg == -4 || ($withpictoimg > -2 && $withpictoimg != 2)) {
3354 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3355 $result .= '<span class="nopadding usertext'.((!isset($this->status) || $this->status) ? '' : ' strikefordisabled').($morecss ? ' '.$morecss : '').'">';
3356 }
3357 if ($mode == 'login') {
3358 $result .= dol_string_nohtmltag(dol_trunc($this->login, $maxlen));
3359 } else {
3360 $result .= dol_string_nohtmltag($this->getFullName($langs, 0, ($mode == 'firstelselast' ? 3 : ($mode == 'firstname' ? 2 : -1)), $maxlen));
3361 }
3362 if (!getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
3363 $result .= '</span>';
3364 }
3365 }
3366 $result .= (($option == 'nolink') ? '' : $linkend);
3367 //if ($withpictoimg == -1) $result.='</div>';
3368
3369 $result .= $companylink;
3370
3371 global $action;
3372 $hookmanager->initHooks(array('userdao'));
3373 $parameters = array('id' => $this->id, 'getnomurl' => &$result);
3374 $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
3375 if ($reshook > 0) {
3376 $result = $hookmanager->resPrint;
3377 } else {
3378 $result .= $hookmanager->resPrint;
3379 }
3380
3381 return $result;
3382 }
3383
3393 public function getLoginUrl($withpictoimg = 0, $option = '', $notooltip = 0, $morecss = '')
3394 {
3395 global $langs, $user;
3396
3397 $result = '';
3398
3399 $linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
3400 $linkend = '</a>';
3401
3402 //Check user's rights to see an other user
3403 if ((!$user->hasRight('user', 'user', 'lire') && $this->id != $user->id)) {
3404 $option = 'nolink';
3405 }
3406
3407 if ($option == 'xxx') {
3408 $linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
3409 $linkend = '</a>';
3410 }
3411
3412 if ($option == 'nolink') {
3413 $linkstart = '';
3414 $linkend = '';
3415 }
3416
3417 $result .= $linkstart;
3418 if ($withpictoimg) {
3419 $paddafterimage = '';
3420 if (abs($withpictoimg) == 1) {
3421 $paddafterimage = 'style="margin-'.($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right').': 3px;"';
3422 }
3423 // Only picto
3424 if ($withpictoimg > 0) {
3425 $picto = '<!-- picto user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'">'.img_object('', 'user', $paddafterimage.' '.($notooltip ? '' : 'class="paddingright classfortooltip"'), 0, 0, $notooltip ? 0 : 1).'</span>';
3426 } else {
3427 // Picto must be a photo
3428 $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>';
3429 }
3430 $result .= $picto;
3431 }
3432 $result .= $this->login;
3433 $result .= $linkend;
3434
3435 return $result;
3436 }
3437
3444 public function getLibStatut($mode = 0)
3445 {
3446 return $this->LibStatut(isset($this->statut) ? (int) $this->statut : (int) $this->status, $mode);
3447 }
3448
3449 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3457 public function LibStatut($status, $mode = 0)
3458 {
3459 // phpcs:enable
3460 global $langs;
3461
3462 if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
3463 global $langs;
3464 //$langs->load("mymodule");
3465 $this->labelStatus[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
3466 $this->labelStatus[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
3467 $this->labelStatusShort[self::STATUS_ENABLED] = $langs->transnoentitiesnoconv('Enabled');
3468 $this->labelStatusShort[self::STATUS_DISABLED] = $langs->transnoentitiesnoconv('Disabled');
3469 }
3470
3471 $statusType = 'status5';
3472 if ($status == self::STATUS_ENABLED) {
3473 $statusType = 'status4';
3474 }
3475
3476 $label = $this->labelStatus[$status];
3477 $labelshort = $this->labelStatusShort[$status];
3478
3479 $now = dol_now();
3480 if (!empty($this->datestartvalidity) && $now < $this->datestartvalidity) {
3481 $statusType = 'status3';
3482 $label .= ' ('.$langs->trans("UserNotYetValid").')';
3483 }
3484 if (!empty($this->dateendvalidity) && $now > ($this->dateendvalidity + 24 * 3600 - 1)) {
3485 $statusType = 'status2';
3486 $label .= ' ('.$langs->trans("UserExpired").')';
3487 }
3488
3489 return dolGetStatus($label, $labelshort, '', $statusType, $mode);
3490 }
3491
3492
3500 public function getKanbanView($option = '', $arraydata = null)
3501 {
3502 global $langs;
3503
3504 $selected = (empty($arraydata['selected']) ? 0 : $arraydata['selected']);
3505
3506 $return = '<div class="box-flex-item box-flex-grow-zero">';
3507 $return .= '<div class="info-box info-box-sm">';
3508 $return .= '<span class="info-box-icon bg-infobox-action">';
3509
3510 $label = '';
3511 if (!empty($this->photo)) {
3512 //$label .= '<div class="photointooltip floatright">';
3513 $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
3514 //$label .= '</div>';
3515 //$label .= '<div style="clear: both;"></div>';
3516 $return .= $label;
3517 } else {
3518 $return .= img_picto('', $this->picto);
3519 }
3520
3521 //$return .= '<i class="fa fa-dol-action"></i>'; // Can be image
3522 $return .= '</span>';
3523 $return .= '<div class="info-box-content">';
3524 $return .= '<span class="info-box-ref inline-block tdoverflowmax150 valignmiddle">'.(method_exists($this, 'getNomUrl') ? $this->getNomUrl(0, '', 0, 0, 24, 0, '', 'valignmiddle') : $this->ref);
3525 if (isModEnabled('multicompany') && $this->admin && !$this->entity) {
3526 $return .= img_picto($langs->trans("SuperAdministratorDesc"), 'superadmin', 'class="valignmiddle paddingright paddingleft"');
3527 } elseif ($this->admin) {
3528 $return .= img_picto($langs->trans("AdministratorDesc"), 'admin', 'class="valignmiddle paddingright paddingleft"');
3529 }
3530 $return .= '</span>';
3531 if ($selected >= 0) {
3532 $return .= '<input id="cb'.$this->id.'" class="flat checkforselect fright" type="checkbox" name="toselect[]" value="'.$this->id.'"'.($selected ? ' checked="checked"' : '').'>';
3533 }
3534 if (property_exists($this, 'label')) {
3535 $return .= '<br><span class="info-box-label opacitymedium">'.$this->label.'</span>';
3536 }
3537 if ($this->email) {
3538 $return .= '<br><span class="info-box-label opacitymedium small">'.img_picto('', 'email').' '.$this->email.'</span>';
3539 }
3540 if (method_exists($this, 'getLibStatut')) {
3541 $return .= '<br><div class="info-box-status">'.$this->getLibStatut(3).'</div>';
3542 }
3543 $return .= '</div>';
3544 $return .= '</div>';
3545 $return .= '</div>';
3546
3547 return $return;
3548 }
3549
3550
3551 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
3552 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3562 public function _load_ldap_dn($info, $mode = 0)
3563 {
3564 // phpcs:enable
3565 global $conf;
3566 $dn = '';
3567 if ($mode == 0) {
3568 $dn = getDolGlobalString('LDAP_KEY_USERS') . "=".$info[getDolGlobalString('LDAP_KEY_USERS')]."," . getDolGlobalString('LDAP_USER_DN');
3569 } elseif ($mode == 1) {
3570 $dn = getDolGlobalString('LDAP_USER_DN');
3571 } elseif ($mode == 2) {
3572 $dn = getDolGlobalString('LDAP_KEY_USERS') . "=".$info[getDolGlobalString('LDAP_KEY_USERS')];
3573 }
3574 return $dn;
3575 }
3576
3577 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
3578 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3584 public function _load_ldap_info()
3585 {
3586 // phpcs:enable
3587 global $conf, $langs;
3588
3589 $info = array();
3590
3591 $socialnetworks = getArrayOfSocialNetworks();
3592
3593 $keymodified = false;
3594
3595 // Object classes
3596 $info["objectclass"] = explode(',', getDolGlobalString('LDAP_USER_OBJECT_CLASS'));
3597
3598 $this->fullname = $this->getFullName($langs);
3599
3600 // Possible LDAP KEY (constname => varname)
3601 $ldapkey = array(
3602 'LDAP_FIELD_FULLNAME' => 'fullname',
3603 'LDAP_FIELD_NAME' => 'lastname',
3604 'LDAP_FIELD_FIRSTNAME' => 'firstname',
3605 'LDAP_FIELD_LOGIN' => 'login',
3606 'LDAP_FIELD_LOGIN_SAMBA' => 'login',
3607 'LDAP_FIELD_PHONE' => 'office_phone',
3608 'LDAP_FIELD_MOBILE' => 'user_mobile',
3609 'LDAP_FIELD_FAX' => 'office_fax',
3610 'LDAP_FIELD_MAIL' => 'email',
3611 'LDAP_FIELD_SID' => 'ldap_sid',
3612 );
3613
3614 // Champs
3615 foreach ($ldapkey as $constname => $varname) {
3616 if (!empty($this->$varname) && getDolGlobalString($constname)) {
3617 $info[getDolGlobalString($constname)] = $this->$varname;
3618
3619 // Check if it is the LDAP key and if its value has been changed
3620 if (getDolGlobalString('LDAP_KEY_USERS') && getDolGlobalString('LDAP_KEY_USERS') == getDolGlobalString($constname)) {
3621 if (is_object($this->oldcopy) && !$this->oldcopy->isEmpty() && $this->$varname != $this->oldcopy->$varname) {
3622 $keymodified = true; // For check if LDAP key has been modified
3623 }
3624 }
3625 }
3626 }
3627 foreach ($socialnetworks as $key => $value) {
3628 if (!empty($this->socialnetworks[$value['label']]) && getDolGlobalString('LDAP_FIELD_'.strtoupper($value['label']))) {
3629 $info[getDolGlobalString('LDAP_FIELD_'.strtoupper($value['label']))] = $this->socialnetworks[$value['label']];
3630 }
3631 }
3632 if ($this->address && getDolGlobalString('LDAP_FIELD_ADDRESS')) {
3633 $info[getDolGlobalString('LDAP_FIELD_ADDRESS')] = $this->address;
3634 }
3635 if ($this->zip && getDolGlobalString('LDAP_FIELD_ZIP')) {
3636 $info[getDolGlobalString('LDAP_FIELD_ZIP')] = $this->zip;
3637 }
3638 if ($this->town && getDolGlobalString('LDAP_FIELD_TOWN')) {
3639 $info[getDolGlobalString('LDAP_FIELD_TOWN')] = $this->town;
3640 }
3641 if ($this->note_public && getDolGlobalString('LDAP_FIELD_DESCRIPTION')) {
3642 $info[getDolGlobalString('LDAP_FIELD_DESCRIPTION')] = dol_string_nohtmltag($this->note_public, 2);
3643 }
3644 if ($this->socid > 0 && getDolGlobalString('LDAP_FIELD_COMPANY')) {
3645 $soc = new Societe($this->db);
3646 $soc->fetch($this->socid);
3647
3648 $info[getDolGlobalString('LDAP_FIELD_COMPANY')] = $soc->name;
3649 if ($soc->client == 1) {
3650 $info["businessCategory"] = "Customers";
3651 }
3652 if ($soc->client == 2) {
3653 $info["businessCategory"] = "Prospects";
3654 }
3655 if ($soc->fournisseur == 1) {
3656 $info["businessCategory"] = "Suppliers";
3657 }
3658 }
3659
3660 // When password is modified
3661 if (!empty($this->pass)) {
3662 if (getDolGlobalString('LDAP_FIELD_PASSWORD')) {
3663 $info[getDolGlobalString('LDAP_FIELD_PASSWORD')] = $this->pass; // this->pass = unencrypted password
3664 }
3665 if (getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')) {
3666 $info[getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')] = dol_hash($this->pass, 'openldap'); // Create OpenLDAP password (see LDAP_PASSWORD_HASH_TYPE)
3667 }
3668 } elseif (getDolGlobalString('LDAP_SERVER_PROTOCOLVERSION') !== '3') {
3669 // Set LDAP password if possible
3670 // If ldap key is modified and LDAPv3 we use ldap_rename function for avoid lose encrypt password
3671 if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
3672 // Just for the default MD5 !
3673 if (!getDolGlobalString('MAIN_SECURITY_HASH_ALGO')) {
3674 if ($this->pass_indatabase_crypted && getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')) {
3675 $info[getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')] = dolGetLdapPasswordHash($this->pass_indatabase_crypted, 'md5frommd5'); // Create OpenLDAP MD5 password from Dolibarr MD5 password
3676 }
3677 }
3678 } elseif (!empty($this->pass_indatabase)) {
3679 // Use $this->pass_indatabase value if exists
3680 if (getDolGlobalString('LDAP_FIELD_PASSWORD')) {
3681 $info[getDolGlobalString('LDAP_FIELD_PASSWORD')] = $this->pass_indatabase; // $this->pass_indatabase = unencrypted password
3682 }
3683 if (getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')) {
3684 $info[getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED')] = dol_hash($this->pass_indatabase, 'openldap'); // Create OpenLDAP password (see LDAP_PASSWORD_HASH_TYPE)
3685 }
3686 }
3687 }
3688
3689 if (getDolGlobalString('LDAP_SERVER_TYPE') == 'egroupware') {
3690 $info["objectclass"][4] = "phpgwContact"; // compatibilite egroupware
3691
3692 $info['uidnumber'] = $this->id;
3693
3694 $info['phpgwTz'] = 0;
3695 $info['phpgwMailType'] = 'INTERNET';
3696 $info['phpgwMailHomeType'] = 'INTERNET';
3697
3698 $info["phpgwContactTypeId"] = 'n';
3699 $info["phpgwContactCatId"] = 0;
3700 $info["phpgwContactAccess"] = "public";
3701
3702 $info["phpgwContactOwner"] = 1;
3703
3704 if ($this->email) {
3705 $info["rfc822Mailbox"] = $this->email;
3706 }
3707 if ($this->user_mobile) {
3708 $info["phpgwCellTelephoneNumber"] = $this->user_mobile;
3709 }
3710 }
3711
3712 if (getDolGlobalString('LDAP_FIELD_USERID')) {
3713 $info[getDolGlobalString('LDAP_FIELD_USERID')] = $this->id;
3714 }
3715 if (getDolGlobalString('LDAP_FIELD_GROUPID')) {
3716 $usergroup = new UserGroup($this->db);
3717 $groupslist = $usergroup->listGroupsForUser($this->id);
3718 $info[getDolGlobalString('LDAP_FIELD_GROUPID')] = '65534';
3719 if (!empty($groupslist)) {
3720 foreach ($groupslist as $groupforuser) {
3721 $info[getDolGlobalString('LDAP_FIELD_GROUPID')] = $groupforuser->id; //Select first group in list
3722 break;
3723 }
3724 }
3725 }
3726 if (getDolGlobalString('LDAP_FIELD_HOMEDIRECTORY') && getDolGlobalString('LDAP_FIELD_HOMEDIRECTORYPREFIX')) {
3727 $info[getDolGlobalString('LDAP_FIELD_HOMEDIRECTORY')] = getDolGlobalString('LDAP_FIELD_HOMEDIRECTORYPREFIX')."/".$this->login;
3728 }
3729
3730 return $info;
3731 }
3732
3733
3741 public function initAsSpecimen()
3742 {
3743 global $user;
3744
3745 $now = dol_now();
3746
3747 // Initialise parameters
3748 $this->id = 0;
3749 $this->ref = 'SPECIMEN';
3750 $this->specimen = 1;
3751 $this->user_creation_id = $user->id;
3752
3753 $this->lastname = 'DOLIBARR';
3754 $this->firstname = 'SPECIMEN';
3755 $this->gender = 'man';
3756 $this->note_public = 'This is a note public';
3757 $this->note_private = 'This is a note private';
3758 $this->email = 'email@specimen.com';
3759 $this->personal_email = 'personalemail@specimen.com';
3760 $this->socialnetworks = array(
3761 'skype' => 'skypepseudo',
3762 'twitter' => 'twitterpseudo',
3763 'facebook' => 'facebookpseudo',
3764 'linkedin' => 'linkedinpseudo',
3765 );
3766 $this->office_phone = '0999999999';
3767 $this->office_fax = '0999999998';
3768 $this->user_mobile = '0999999997';
3769 $this->personal_mobile = '0999999996';
3770 $this->admin = 0;
3771 $this->login = 'dolibspec';
3772 $this->pass = 'dolibSpec+@123';
3773 //$this->pass_indatabase='dolibspec'; Set after a fetch
3774 //$this->pass_indatabase_crypted='e80ca5a88c892b0aaaf7e154853bccab'; Set after a fetch
3775 $this->datec = $now;
3776 $this->datem = $now;
3777
3778 $this->datelastlogin = $now;
3779 $this->iplastlogin = '127.0.0.1';
3780 $this->datepreviouslogin = $now;
3781 $this->ippreviouslogin = '127.0.0.1';
3782 $this->status = 1;
3783
3784 $this->entity = 1;
3785
3786 return 1;
3787 }
3788
3795 public function info($id)
3796 {
3797 $sql = "SELECT u.rowid, u.login as ref, u.datec, fk_user_creat as user_creation_id, fk_user_modif as user_modification_id,";
3798 $sql .= " GREATEST(u.tms, uef.tms) as date_modification, u.entity";
3799 $sql .= " FROM ".$this->db->prefix()."user as u";
3800 $sql .= " LEFT JOIN ".$this->db->prefix()."user_extrafields as uef ON uef.fk_object = u.rowid";
3801 $sql .= " WHERE u.rowid = ".((int) $id);
3802
3803 $result = $this->db->query($sql);
3804 if ($result) {
3805 if ($this->db->num_rows($result)) {
3806 $obj = $this->db->fetch_object($result);
3807
3808 $this->id = $obj->rowid;
3809
3810 $this->user_creation_id = $obj->user_creation_id;
3811 $this->user_modification_id = $obj->user_modification_id;
3812
3813 $this->ref = (!$obj->ref) ? $obj->rowid : $obj->ref;
3814 $this->date_creation = $this->db->jdate($obj->datec);
3815 $this->date_modification = $this->db->jdate($obj->date_modification);
3816 $this->entity = $obj->entity;
3817 }
3818
3819 $this->db->free($result);
3820 } else {
3821 dol_print_error($this->db);
3822 }
3823 }
3824
3825
3831 public function getNbOfEMailings()
3832 {
3833 $sql = "SELECT count(mc.email) as nb";
3834 $sql .= " FROM ".$this->db->prefix()."mailing_cibles as mc";
3835 $sql .= " WHERE mc.email = '".$this->db->escape($this->email)."'";
3836 $sql .= " AND mc.statut NOT IN (-1,0)"; // -1 error, 0 not sent, 1 sent with success
3837
3838 $resql = $this->db->query($sql);
3839 if ($resql) {
3840 $obj = $this->db->fetch_object($resql);
3841 $nb = (int) $obj->nb;
3842
3843 $this->db->free($resql);
3844 return $nb;
3845 } else {
3846 $this->error = $this->db->error();
3847 return -1;
3848 }
3849 }
3850
3859 public function getNbOfUsers($limitTo, $option = '', $admin = -1)
3860 {
3861 $sql = "SELECT count(rowid) as nb";
3862 $sql .= " FROM ".$this->db->prefix()."user";
3863 if ($option == 'superadmin') {
3864 $sql .= " WHERE entity = 0";
3865 } else {
3866 $sql .= " WHERE entity IN (".getEntity('user', 0).")";
3867 if ($limitTo == 'active') {
3868 $sql .= " AND statut = 1";
3869 }
3870 }
3871 if ($admin >= 0) {
3872 $sql .= " AND admin = ".(int) $admin;
3873 }
3874
3875 $resql = $this->db->query($sql);
3876 if ($resql) {
3877 $obj = $this->db->fetch_object($resql);
3878 $nb = (int) $obj->nb;
3879
3880 $this->db->free($resql);
3881 return $nb;
3882 } else {
3883 $this->error = $this->db->lasterror();
3884 return -1;
3885 }
3886 }
3887
3888 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3895 public function update_ldap2dolibarr(&$ldapuser)
3896 {
3897 // phpcs:enable
3898 // TODO: See why the update sets all values to empty (does global $user overwrite?)
3899 global $user;
3900
3901 $socialnetworks = getArrayOfSocialNetworks();
3902
3903 $tmpvar = getDolGlobalString('LDAP_FIELD_FIRSTNAME');
3904 $this->firstname = $ldapuser->$tmpvar;
3905 $tmpvar = getDolGlobalString('LDAP_FIELD_NAME');
3906 $this->lastname = $ldapuser->$tmpvar;
3907 $tmpvar = getDolGlobalString('LDAP_FIELD_LOGIN');
3908 $this->login = $ldapuser->$tmpvar;
3909 $tmpvar = getDolGlobalString('LDAP_FIELD_PASSWORD');
3910 $this->pass = $ldapuser->$tmpvar;
3911 $tmpvar = getDolGlobalString('LDAP_FIELD_PASSWORD_CRYPTED');
3912 $this->pass_indatabase_crypted = $ldapuser->$tmpvar;
3913
3914 $tmpvar = getDolGlobalString('LDAP_FIELD_PHONE');
3915 $this->office_phone = $ldapuser->$tmpvar;
3916 $tmpvar = getDolGlobalString('LDAP_FIELD_MOBILE');
3917 $this->user_mobile = $ldapuser->$tmpvar;
3918 $tmpvar = getDolGlobalString('LDAP_FIELD_FAX');
3919 $this->office_fax = $ldapuser->$tmpvar;
3920 $tmpvar = getDolGlobalString('LDAP_FIELD_MAIL');
3921 $this->email = $ldapuser->$tmpvar;
3922 foreach ($socialnetworks as $key => $value) {
3923 $tmpvar = getDolGlobalString('LDAP_FIELD_'.strtoupper($value['label']));
3924 $this->socialnetworks[$value['label']] = $ldapuser->$tmpvar;
3925 }
3926 $tmpvar = getDolGlobalString('LDAP_FIELD_SID');
3927 $this->ldap_sid = $ldapuser->$tmpvar;
3928
3929 $tmpvar = getDolGlobalString('LDAP_FIELD_TITLE');
3930 $this->job = $ldapuser->$tmpvar;
3931 $tmpvar = getDolGlobalString('LDAP_FIELD_DESCRIPTION');
3932 $this->note_public = $ldapuser->$tmpvar;
3933
3934 $result = $this->update($user);
3935
3936 dol_syslog(get_class($this)."::update_ldap2dolibarr result=".$result, LOG_DEBUG);
3937
3938 return $result;
3939 }
3940
3941
3942 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3949 public function get_children()
3950 {
3951 // phpcs:enable
3952 $sql = "SELECT rowid FROM ".$this->db->prefix()."user";
3953 $sql .= " WHERE fk_user = ".((int) $this->id);
3954
3955 dol_syslog(get_class($this)."::get_children", LOG_DEBUG);
3956 $res = $this->db->query($sql);
3957 if ($res) {
3958 $users = array();
3959 while ($rec = $this->db->fetch_array($res)) {
3960 $user = new User($this->db);
3961 $user->fetch($rec['rowid']);
3962 $users[] = $user;
3963 }
3964 return $users;
3965 } else {
3966 dol_print_error($this->db);
3967 return -1;
3968 }
3969 }
3970
3971
3977 private function loadParentOf()
3978 {
3979 $this->parentof = array();
3980
3981 // Load array[child]=parent
3982 $sql = "SELECT fk_user as id_parent, rowid as id_son";
3983 $sql .= " FROM ".$this->db->prefix()."user";
3984 $sql .= " WHERE fk_user <> 0";
3985 $sql .= " AND entity IN (".getEntity('user').")";
3986
3987 dol_syslog(get_class($this)."::loadParentOf", LOG_DEBUG);
3988 $resql = $this->db->query($sql);
3989 if ($resql) {
3990 while ($obj = $this->db->fetch_object($resql)) {
3991 $this->parentof[$obj->id_son] = $obj->id_parent;
3992 }
3993 return 1;
3994 } else {
3995 dol_print_error($this->db);
3996 return -1;
3997 }
3998 }
3999
4000 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4014 public function get_full_tree($deleteafterid = 0, $filter = '')
4015 {
4016 // phpcs:enable
4017 global $hookmanager;
4018
4019 // Actions hooked (by external module)
4020 $hookmanager->initHooks(array('userdao'));
4021
4022 $this->users = array();
4023
4024 // Init this->parentof that is array(id_son=>id_parent, ...)
4025 $this->loadParentOf();
4026
4027 // Init $this->users array
4028 $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
4029 $sql .= " FROM ".$this->db->prefix()."user as u";
4030 // Add fields from hooks
4031 $parameters = array();
4032 $reshook = $hookmanager->executeHooks('printUserListWhere', $parameters); // Note that $action and $object may have been modified by hook
4033 if ($reshook > 0) {
4034 $sql .= $hookmanager->resPrint;
4035 } else {
4036 $sql .= " WHERE u.entity IN (".getEntity('user').")";
4037 }
4038 if ($filter) {
4039 $sql .= forgeSQLFromUniversalSearchCriteria($filter);
4040 }
4041
4042 dol_syslog(get_class($this)."::get_full_tree get user list", LOG_DEBUG);
4043 $resql = $this->db->query($sql);
4044 if ($resql) {
4045 $i = 0;
4046 while ($obj = $this->db->fetch_object($resql)) {
4047 $this->users[(int) $obj->rowid]
4048 = array(
4049 'rowid' => (int) $obj->rowid,
4050 'id' => (int) $obj->rowid,
4051 'fk_user' => (int) $obj->fk_user,
4052 'fk_soc' => (int) $obj->fk_soc,
4053 'firstname' => (string) $obj->firstname,
4054 'lastname' => (string) $obj->lastname,
4055 'login' => (string) $obj->login,
4056 'statut' => (int) $obj->statut,
4057 'entity' => (int) $obj->entity,
4058 'email' => (string) $obj->email,
4059 'gender' => (string) $obj->gender,
4060 'admin' => (int) $obj->admin,
4061 'photo' => (string) $obj->photo,
4062 // fields are filled with build_path_from_id_user
4063 'fullpath' => '',
4064 'fullname' => '',
4065 'level' => 0,
4066 );
4067 $i++;
4068 }
4069 } else {
4070 dol_print_error($this->db);
4071 return -1;
4072 }
4073
4074 // We add the fullpath property to each element of the first level (no parent exists)
4075 dol_syslog(get_class($this)."::get_full_tree call to build_path_from_id_user", LOG_DEBUG);
4076 foreach ($this->users as $key => $val) {
4077 $result = $this->build_path_from_id_user($key, 0); // Process a branch from the root user key (this user has no parent)
4078 if ($result < 0) {
4079 $this->error = 'ErrorLoopInHierarchy';
4080 return -1;
4081 }
4082 }
4083
4084 // Exclude leaf including $deleteafterid from tree
4085 if ($deleteafterid) {
4086 //print "Look to discard user ".$deleteafterid."\n";
4087 $keyfilter1 = '^'.$deleteafterid.'$';
4088 $keyfilter2 = '_'.$deleteafterid.'$';
4089 $keyfilter3 = '^'.$deleteafterid.'_';
4090 $keyfilter4 = '_'.$deleteafterid.'_';
4091 foreach (array_keys($this->users) as $key) {
4092 $fullpath = (string) $this->users[$key]['fullpath'];
4093 if (preg_match('/'.$keyfilter1.'/', $fullpath) || preg_match('/'.$keyfilter2.'/', $fullpath)
4094 || preg_match('/'.$keyfilter3.'/', $fullpath) || preg_match('/'.$keyfilter4.'/', $fullpath)) {
4095 unset($this->users[$key]);
4096 }
4097 }
4098 }
4099
4100 dol_syslog(get_class($this)."::get_full_tree dol_sort_array", LOG_DEBUG);
4101 $this->users = dol_sort_array($this->users, 'fullname', 'asc', 1, 0, 1);
4102
4103 return $this->users;
4104 }
4105
4114 public function getAllChildIds($addcurrentuser = 0)
4115 {
4116 $childids = array();
4117
4118 if (isset($this->cache_childids[$this->id])) {
4119 $childids = $this->cache_childids[$this->id];
4120 } else {
4121 // Init this->users
4122 $this->get_full_tree();
4123
4124 $idtoscan = $this->id;
4125
4126 dol_syslog("Build childid for id = ".$idtoscan);
4127 foreach ($this->users as $id => $val) {
4128 if (preg_match('/_'.$idtoscan.'_/', $val['fullpath'])) {
4129 $childids[$val['id']] = $val['id'];
4130 }
4131 }
4132 }
4133 $this->cache_childids[$this->id] = $childids;
4134
4135 if ($addcurrentuser) {
4136 $childids[$this->id] = $this->id;
4137 }
4138
4139 return $childids;
4140 }
4141
4142 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4151 public function build_path_from_id_user($id_user, $protection = 0)
4152 {
4153 // phpcs:enable
4154 //dol_syslog(get_class($this)."::build_path_from_id_user id_user=".$id_user." protection=".$protection, LOG_DEBUG);
4155
4156 if (!empty($this->users[$id_user]['fullpath'])) {
4157 // Already defined
4158 dol_syslog(get_class($this)."::build_path_from_id_user fullpath and fullname already defined", LOG_WARNING);
4159 return 0;
4160 }
4161
4162 // Define fullpath and fullname
4163 $this->users[$id_user]['fullpath'] = '_'.$id_user;
4164 $this->users[$id_user]['fullname'] = $this->users[$id_user]['lastname'];
4165 $i = 0;
4166 $cursor_user = $id_user;
4167
4168 $useridfound = array($id_user);
4169 while (!empty($this->parentof[$cursor_user]) && !empty($this->users[$this->parentof[$cursor_user]])) { // @phan-suppress-current-line PhanTypeMismatchProperty
4170 if (in_array($this->parentof[$cursor_user], $useridfound)) {
4171 dol_syslog("The hierarchy of user has a recursive loop", LOG_WARNING);
4172 return -1; // Should not happen. Protection against looping hierarchy
4173 }
4174 $useridfound[] = $this->parentof[$cursor_user];
4175 $this->users[$id_user]['fullpath'] = '_'.$this->parentof[$cursor_user].$this->users[$id_user]['fullpath'];
4176 $this->users[$id_user]['fullname'] = $this->users[$this->parentof[$cursor_user]]['lastname'].' >> '.$this->users[$id_user]['fullname'];
4177 $i++;
4178 $cursor_user = $this->parentof[$cursor_user];
4179 }
4180
4181 // We count number of _ to have level
4182 $this->users[$id_user]['level'] = dol_strlen(preg_replace('/[^_]/i', '', $this->users[$id_user]['fullpath']));
4183
4184 return 1;
4185 }
4186
4195 public static function replaceThirdparty(DoliDB $dbs, $origin_id, $dest_id)
4196 {
4197 $tables = array(
4198 'user',
4199 );
4200
4201 return CommonObject::commonReplaceThirdparty($dbs, $origin_id, $dest_id, $tables);
4202 }
4203
4214 public static function replaceContact(DoliDB $dbs, $origin_id, $dest_id)
4215 {
4216 if (!CommonObject::commonReplaceContact($dbs, $origin_id, $dest_id, array('user'))) {
4217 return false;
4218 }
4219
4220 return CommonObject::commonReplaceContact($dbs, $origin_id, $dest_id, array('user_alert'), 'fk_contact');
4221 }
4222
4223
4229 public function loadStateBoard()
4230 {
4231 $this->nb = array();
4232
4233 $sql = "SELECT COUNT(DISTINCT u.rowid) as nb";
4234 $sql .= " FROM ".$this->db->prefix()."user as u";
4235 if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
4236 $sql .= ", ".$this->db->prefix()."usergroup_user as ug";
4237 $sql .= " WHERE ug.entity IN (".getEntity('usergroup').")";
4238 $sql .= " AND ug.fk_user = u.rowid";
4239 } else {
4240 $sql .= " WHERE u.entity IN (".getEntity('user').")";
4241 }
4242 $sql .= " AND u.statut > 0";
4243 //$sql.= " AND employee != 0";
4244
4245 $resql = $this->db->query($sql);
4246 if ($resql) {
4247 while ($obj = $this->db->fetch_object($resql)) {
4248 $this->nb["users"] = $obj->nb;
4249 }
4250 $this->db->free($resql);
4251 return 1;
4252 } else {
4253 dol_print_error($this->db);
4254 $this->error = $this->db->error();
4255 return -1;
4256 }
4257 }
4258
4270 public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
4271 {
4272 global $langs;
4273
4274 $langs->load("user");
4275
4276 // Set the '$modele' to the name of the document template (model) to use
4277 if (!dol_strlen($modele)) {
4278 if (getDolGlobalString('USER_ADDON_PDF')) {
4279 $modele = getDolGlobalString('USER_ADDON_PDF');
4280 } else {
4281 $modele = 'bluesky';
4282 }
4283 }
4284
4285 $modelpath = "core/modules/user/doc/";
4286
4287 return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
4288 }
4289
4290 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
4298 public function user_get_property($rowid, $mode)
4299 {
4300 // phpcs:enable
4301 $user_property = '';
4302
4303 if (empty($rowid)) {
4304 return '';
4305 }
4306
4307 $sql = "SELECT rowid, email, user_mobile, civility, lastname, firstname";
4308 $sql .= " FROM ".$this->db->prefix()."user";
4309 $sql .= " WHERE rowid = ".((int) $rowid);
4310
4311 $resql = $this->db->query($sql);
4312 if ($resql) {
4313 $nump = $this->db->num_rows($resql);
4314
4315 if ($nump) {
4316 $obj = $this->db->fetch_object($resql);
4317
4318 if ($mode == 'email') {
4319 $user_property = dolGetFirstLastname($obj->firstname, $obj->lastname)." <".$obj->email.">";
4320 } elseif ($mode == 'mobile') {
4321 $user_property = $obj->user_mobile;
4322 } elseif ($mode == 'name') {
4323 $user_property = dolGetFirstLastname($obj->firstname, $obj->lastname);
4324 }
4325 }
4326 return $user_property;
4327 } else {
4328 dol_print_error($this->db);
4329 }
4330
4331 return '';
4332 }
4333
4341 public function getOnlineVirtualCardUrl($mode = '', $typeofurl = 'external')
4342 {
4344 global $conf;
4345
4346 $instanceuniqueid = empty($conf->file->instance_unique_id) ? '' : $conf->file->instance_unique_id;
4347 $encodedsecurekey = dol_hash($instanceuniqueid.'uservirtualcard'.$this->id.'-'.$this->login, 'md5');
4348 if (isModEnabled('multicompany')) {
4349 $entity_qr = '&entity='.((int) $conf->entity);
4350 } else {
4351 $entity_qr = '';
4352 }
4353 // Define $urlwithroot
4354 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
4355 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
4356 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
4357
4358 if ($typeofurl == 'internal') {
4359 $urlwithroot = DOL_URL_ROOT;
4360 }
4361
4362 return $urlwithroot.'/public/users/view.php?id='.$this->id.'&securekey='.$encodedsecurekey.$entity_qr.($mode ? '&mode='.urlencode($mode) : '');
4363 }
4364
4378 public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND', $entityfilter = false)
4379 {
4380 global $conf, $user;
4381
4382 $sql = "SELECT t.rowid";
4383 $sql .= ' FROM '.$this->db->prefix().$this->table_element.' as t ';
4384
4385 if ($entityfilter) {
4386 if (getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
4387 if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
4388 $sql .= " WHERE t.entity IS NOT NULL"; // Show all users
4389 } else {
4390 $sql .= " WHERE t.entity = 0 OR EXISTS (";
4391 $sql .= " SELECT ug.rowid FROM " . $this->db->prefix() . "usergroup_user as ug";
4392 $sql .= " WHERE ug.fk_user = t.rowid AND ug.entity IN (" . getEntity('usergroup') . "))";
4393 }
4394 } else {
4395 $sql .= " WHERE t.entity IN (".getEntity('user').")";
4396 }
4397 } else {
4398 $sql .= " WHERE 1 = 1";
4399 }
4400
4401 // Manage filter
4402 $errormessage = '';
4403 $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
4404 if ($errormessage) {
4405 $this->errors[] = $errormessage;
4406 dol_syslog(__METHOD__.' '.implode(',', $this->errors), LOG_ERR);
4407 return -1;
4408 }
4409
4410 $sql .= $this->db->order($sortfield, $sortorder);
4411 if ($limit) {
4412 $sql .= $this->db->plimit($limit + 1, $offset);
4413 }
4414
4415 dol_syslog(__METHOD__, LOG_DEBUG);
4416
4417 $resql = $this->db->query($sql);
4418 if ($resql) {
4419 $this->users = array();
4420 $num = $this->db->num_rows($resql);
4421 if ($num) {
4422 while ($obj = $this->db->fetch_object($resql)) {
4423 $line = new self($this->db);
4424 $result = $line->fetch($obj->rowid);
4425 if ($result > 0 && !empty($line->id)) {
4426 $this->users[$obj->rowid] = clone $line;
4427 }
4428 }
4429 $this->db->free($resql);
4430 }
4431 return $num;
4432 } else {
4433 $this->errors[] = $this->db->lasterror();
4434 return -1;
4435 }
4436 }
4437
4445 private $findUserIdByEmailCache;
4446
4457 public function findUserIdByEmail($email)
4458 {
4459 if (isset($this->findUserIdByEmailCache[$email])) {
4460 return $this->findUserIdByEmailCache[$email];
4461 }
4462
4463 $this->findUserIdByEmailCache[$email] = -1;
4464
4465 $sql = 'SELECT rowid';
4466 $sql .= ' FROM '.$this->db->prefix().'user';
4467 if (getDolGlobalString('AGENDA_DISABLE_EXACT_USER_EMAIL_COMPARE_FOR_EXTERNAL_CALENDAR')) {
4468 $sql .= " WHERE email LIKE '%".$this->db->escape($this->db->escapeforlike($email))."%'";
4469 } else {
4470 $sql .= " WHERE email = '".$this->db->escape($email)."'";
4471 }
4472 $sql .= ' LIMIT 1';
4473
4474 $resql = $this->db->query($sql);
4475 if (!$resql) {
4476 return -1;
4477 }
4478
4479 $obj = $this->db->fetch_object($resql);
4480 if (!$obj) {
4481 return -1;
4482 }
4483
4484 $this->findUserIdByEmailCache[$email] = (int) $obj->rowid;
4485
4486 return $this->findUserIdByEmailCache[$email];
4487 }
4488
4495 public function cloneRights($fromId, $toId)
4496 {
4497 if (empty($fromId) || empty($toId)) {
4498 return -1;
4499 }
4500
4501 $this->db->begin();
4502
4503 // delete default rights for UserTo
4504 $sqlDelete = "DELETE FROM ".$this->db->prefix()."user_rights";
4505 $sqlDelete .= " WHERE fk_user = ".((int) $toId);
4506
4507 dol_syslog(get_class($this)."::clone_rights (delete default permissions)", LOG_DEBUG);
4508
4509 if (!$this->db->query($sqlDelete)) {
4510 $this->db->rollback();
4511 return -1;
4512 }
4513
4514 // Construction of the insertion request
4515 $sql = "INSERT INTO ".$this->db->prefix()."user_rights (entity, fk_user, fk_id)";
4516 $sql .= " SELECT entity, ".((int) $toId).", fk_id";
4517 $sql .= " FROM ".$this->db->prefix()."user_rights src";
4518 $sql .= " WHERE fk_user = ".((int) $fromId);
4519 $sql .= " AND NOT EXISTS (";
4520 $sql .= " SELECT 1";
4521 $sql .= " FROM ".$this->db->prefix()."user_rights dest";
4522 $sql .= " WHERE dest.entity = src.entity";
4523 $sql .= " AND dest.fk_user = ".((int) $toId);
4524 $sql .= " AND dest.fk_id = src.fk_id";
4525 $sql .= " )";
4526
4527 dol_syslog(get_class($this)."::clone_rights", LOG_DEBUG);
4528
4529 // Execute request
4530 if (!$this->db->query($sql)) {
4531 $this->db->rollback();
4532 return -1;
4533 }
4534
4535 $this->db->commit();
4536 return 1;
4537 }
4538
4547 public function cloneCategories($fromId, $toId, $type = 'user')
4548 {
4549 $this->db->begin();
4550
4551 if (empty($type)) {
4552 $type = $this->table_element;
4553 }
4554
4555 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
4556 $categorystatic = new Categorie($this->db);
4557
4558 $sql = "INSERT INTO ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type])." (fk_categorie, fk_user)";
4559 $sql .= " SELECT fk_categorie, ".((int) $toId)." FROM ".$this->db->prefix()."categorie_".(empty($categorystatic->MAP_CAT_TABLE[$type]) ? $type : $categorystatic->MAP_CAT_TABLE[$type]);
4560 $sql .= " WHERE fk_user = ".((int) $fromId);
4561
4562 if (!$this->db->query($sql)) {
4563 $this->error = $this->db->lasterror();
4564 $this->db->rollback();
4565 return -1;
4566 }
4567
4568 $this->db->commit();
4569 return 1;
4570 }
4571}
global $dolibarr_main_url_root
$c
Definition line.php:334
$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
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:665
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:651
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
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
picto_from_langcode($codelang, $moreatt='', $notitlealt=0)
Return img flag of country for a language code or country code.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
yn($yesno, $format=1, $color=0)
Return yes or no in current language.
dolGetStatus($statusLabel='', $statusLabelShort='', $html='', $statusType='status0', $displayMode=0, $url='', $params=array())
Output the badge of a status.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
conf($dolibarr_main_document_root, $realpathconf=null)
Load conf file (file must exists)
Definition inc.php:431
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
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.