Passed
Branch develop (5cbde9)
by
unknown
26:38
created

User::fetch_clicktodial()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 17
c 0
b 0
f 0
nc 3
nop 0
dl 0
loc 29
rs 9.7
1
<?php
2
/* Copyright (c) 2002-2007  Rodolphe Quiedeville    <[email protected]>
3
 * Copyright (c) 2002-2003  Jean-Louis Bergamo      <[email protected]>
4
 * Copyright (c) 2004-2012  Laurent Destailleur     <[email protected]>
5
 * Copyright (C) 2004       Sebastien Di Cintio     <[email protected]>
6
 * Copyright (C) 2004       Benoit Mortier          <[email protected]>
7
 * Copyright (C) 2005-2017  Regis Houssin           <[email protected]>
8
 * Copyright (C) 2005       Lionel Cousteix         <[email protected]>
9
 * Copyright (C) 2011       Herve Prot              <[email protected]>
10
 * Copyright (C) 2013-2019  Philippe Grand          <[email protected]>
11
 * Copyright (C) 2013-2015  Alexandre Spangaro      <[email protected]>
12
 * Copyright (C) 2015       Marcos García           <[email protected]>
13
 * Copyright (C) 2018       charlene Benke          <[email protected]>
14
 * Copyright (C) 2018       Nicolas ZABOURI         <[email protected]>
15
 * Copyright (C) 2019       Frédéric France         <[email protected]>
16
 *
17
 * This program is free software; you can redistribute it and/or modify
18
 * it under the terms of the GNU General Public License as published by
19
 * the Free Software Foundation; either version 3 of the License, or
20
 * (at your option) any later version.
21
 *
22
 * This program is distributed in the hope that it will be useful,
23
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25
 * GNU General Public License for more details.
26
 *
27
 * You should have received a copy of the GNU General Public License
28
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29
 */
30
31
/**
32
 *  \file       htdocs/user/class/user.class.php
33
 *	\brief      File of class to manage users
34
 *  \ingroup	core
35
 */
36
37
require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
38
39
/**
40
 *	Class to manage Dolibarr users
41
 */
42
class User extends CommonObject
43
{
44
	/**
45
	 * @var string ID to identify managed object
46
	 */
47
	public $element='user';
48
49
	/**
50
	 * @var string Name of table without prefix where object is stored
51
	 */
52
	public $table_element='user';
53
54
	/**
55
	 * @var int Field with ID of parent key if this field has a parent
56
	 */
57
	public $fk_element='fk_user';
58
59
	/**
60
	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
61
	 * @var int
62
	 */
63
	public $ismultientitymanaged = 1;
64
65
	public $id=0;
66
	public $statut;
67
	public $ldap_sid;
68
	public $search_sid;
69
	public $employee;
70
	public $gender;
71
	public $birth;
72
	public $email;
73
	public $personal_email;
74
75
	public $skype;
76
	public $twitter;
77
	public $facebook;
78
	public $linkedin;
79
80
	public $job;			// job position
81
	public $signature;
82
83
	/**
84
	 * @var string Address
85
	 */
86
	public $address;
87
88
	public $zip;
89
	public $town;
90
	public $state_id;		// The state/department
91
	public $state_code;
92
	public $state;
93
	public $office_phone;
94
	public $office_fax;
95
	public $user_mobile;
96
    public $personal_mobile;
97
	public $admin;
98
	public $login;
99
	public $api_key;
100
101
	/**
102
	 * @var int Entity
103
	 */
104
	public $entity;
105
106
	//! Clear password in memory
107
	public $pass;
108
	//! Clear password in database (defined if DATABASE_PWD_ENCRYPTED=0)
109
	public $pass_indatabase;
110
	//! Encrypted password in database (always defined)
111
	public $pass_indatabase_crypted;
112
113
	/**
114
     * Date creation record (datec)
115
     *
116
     * @var integer
117
     */
118
    public $datec;
119
120
	/**
121
     * Date modification record (tms)
122
     *
123
     * @var integer
124
     */
125
    public $datem;
126
127
	//! If this is defined, it is an external user
128
	/**
129
	 * @deprecated
130
	 * @see $socid
131
	 */
132
	public $societe_id;
133
	/**
134
	 * @deprecated
135
	 * @see $contactid
136
	 */
137
	public $contact_id;
138
	public $socid;
139
	public $contactid;
140
141
	/**
142
     * @var int ID
143
     */
144
	public $fk_member;
145
146
	/**
147
	 * @var int User ID
148
	 */
149
	public $fk_user;
150
	public $fk_user_expense_validator;
151
    public $fk_user_holiday_validator;
152
153
	public $clicktodial_url;
154
	public $clicktodial_login;
155
	public $clicktodial_password;
156
	public $clicktodial_poste;
157
158
	public $datelastlogin;
159
	public $datepreviouslogin;
160
	public $photo;
161
	public $lang;
162
163
	public $rights;                        // Array of permissions user->rights->permx
164
	public $all_permissions_are_loaded;	   // All permission are loaded
165
	public $nb_rights;			           // Number of rights granted to the user
166
	private $_tab_loaded=array();		   // Cache array of already loaded permissions
167
168
	public $conf;           		// To store personal config
169
	public $default_values;         // To store default values for user
170
	public $lastsearch_values_tmp;  // To store current search criterias for user
171
	public $lastsearch_values;      // To store last saved search criterias for user
172
173
	public $users = array();		// To store all tree of users hierarchy
174
	public $parentof;				// To store an array of all parents for all ids.
175
	private $cache_childids;
176
177
	public $accountancy_code;			// Accountancy code in prevision of the complete accountancy module
178
179
	public $thm;					// Average cost of employee - Used for valuation of time spent
180
	public $tjm;					// Average cost of employee
181
182
	public $salary;					// Monthly salary       - Denormalized value from llx_user_employment
183
	public $salaryextra;				// Monthly salary extra - Denormalized value from llx_user_employment
184
	public $weeklyhours;				// Weekly hours         - Denormalized value from llx_user_employment
185
186
	public $color;						// Define background color for user in agenda
187
188
	public $dateemployment;			// Define date of employment by company
189
	public $dateemploymentend;		// Define date of employment end by company
190
191
	public $default_c_exp_tax_cat;
192
	public $default_range;
193
194
	public $fk_warehouse;
195
196
	public $fields = array(
197
        'rowid'=>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1,  'index'=>1, 'position'=>1, 'comment'=>'Id'),
198
        'lastname'=>array('type'=>'varchar(50)', 'label'=>'Name', 'enabled'=>1, 'visible'=>1,  'notnull'=>1,  'showoncombobox'=>1, 'index'=>1, 'position'=>20, 'searchall'=>1, 'comment'=>'Reference of object'),
199
        'firstname'=>array('type'=>'varchar(50)', 'label'=>'Name','enabled'=>1, 'visible'=>1,  'notnull'=>1,  'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1, 'comment'=>'Reference of object'),
200
    );
201
202
	/**
203
	 *    Constructor of the class
204
	 *
205
	 *    @param   DoliDb  $db     Database handler
206
	 */
207
	public function __construct($db)
208
	{
209
		$this->db = $db;
210
211
		// User preference
212
		$this->liste_limit = 0;
213
		$this->clicktodial_loaded = 0;
214
215
		// For cache usage
216
		$this->all_permissions_are_loaded = 0;
217
		$this->nb_rights = 0;
218
219
		// Force some default values
220
		$this->admin = 0;
221
		$this->employee = 1;
222
223
		$this->conf = new stdClass();
224
		$this->rights = new stdClass();
225
		$this->rights->user = new stdClass();
226
		$this->rights->user->user = new stdClass();
227
		$this->rights->user->self = new stdClass();
228
	}
229
230
	/**
231
	 *	Load a user from database with its id or ref (login).
232
	 *  This function does not load permissions, only user properties. Use getrights() for this just after the fetch.
233
	 *
234
	 *	@param	int		$id		       		If defined, id to used for search
235
	 * 	@param  string	$login       		If defined, login to used for search
236
	 *	@param  string	$sid				If defined, sid to used for search
237
	 * 	@param	int		$loadpersonalconf	1=also load personal conf of user (in $user->conf->xxx), 0=do not load personal conf.
238
	 *  @param  int     $entity             If a value is >= 0, we force the search on a specific entity. If -1, means search depens on default setup.
239
	 * 	@return	int							<0 if KO, 0 not found, >0 if OK
240
	 */
241
	public function fetch($id = '', $login = '', $sid = '', $loadpersonalconf = 0, $entity = -1)
242
	{
243
		global $conf, $user;
244
245
		// Clean parameters
246
		$login=trim($login);
247
248
		// Get user
249
		$sql = "SELECT u.rowid, u.lastname, u.firstname, u.employee, u.gender, u.birth, u.email, u.personal_email, u.job, u.skype, u.twitter, u.facebook, u.linkedin,";
250
		$sql.= " u.signature, u.office_phone, u.office_fax, u.user_mobile, u.personal_mobile,";
251
		$sql.= " u.address, u.zip, u.town, u.fk_state as state_id, u.fk_country as country_id,";
252
		$sql.= " u.admin, u.login, u.note,";
253
		$sql.= " u.pass, u.pass_crypted, u.pass_temp, u.api_key,";
254
		$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,";
255
		$sql.= " u.statut, u.lang, u.entity,";
256
		$sql.= " u.datec as datec,";
257
		$sql.= " u.tms as datem,";
258
		$sql.= " u.datelastlogin as datel,";
259
		$sql.= " u.datepreviouslogin as datep,";
260
		$sql.= " u.photo as photo,";
261
		$sql.= " u.openid as openid,";
262
		$sql.= " u.accountancy_code,";
263
		$sql.= " u.thm,";
264
		$sql.= " u.tjm,";
265
		$sql.= " u.salary,";
266
		$sql.= " u.salaryextra,";
267
		$sql.= " u.weeklyhours,";
268
		$sql.= " u.color,";
269
		$sql.= " u.dateemployment, u.dateemploymentend,";
270
		$sql.= " u.fk_warehouse,";
271
		$sql.= " u.ref_int, u.ref_ext,";
272
		$sql.= " u.default_range, u.default_c_exp_tax_cat,";			// Expense report default mode
273
		$sql.= " c.code as country_code, c.label as country,";
274
		$sql.= " d.code_departement as state_code, d.nom as state";
275
		$sql.= " FROM ".MAIN_DB_PREFIX."user as u";
276
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON u.fk_country = c.rowid";
277
		$sql.= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as d ON u.fk_state = d.rowid";
278
279
		if ($entity < 0)
280
		{
281
			if ((empty($conf->multicompany->enabled) || empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) && (! empty($user->entity)))
282
			{
283
				$sql.= " WHERE u.entity IN (0,".$conf->entity.")";
284
			}
285
			else
286
			{
287
				$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
288
			}
289
		}
290
		else  // The fetch was forced on an entity
291
		{
292
			if (!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
293
				$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
294
			else
295
				$sql.= " WHERE u.entity IN (0, ".(($entity!='' && $entity >= 0)?$entity:$conf->entity).")";   // search in entity provided in parameter
296
		}
297
298
		if ($sid)    // permet une recherche du user par son SID ActiveDirectory ou Samba
299
		{
300
			$sql.= " AND (u.ldap_sid = '".$this->db->escape($sid)."' OR u.login = '".$this->db->escape($login)."') LIMIT 1";
301
		}
302
		elseif ($login)
303
		{
304
			$sql.= " AND u.login = '".$this->db->escape($login)."'";
305
		}
306
		else
307
		{
308
			$sql.= " AND u.rowid = ".$id;
309
		}
310
		$sql.= " ORDER BY u.entity ASC";    // Avoid random result when there is 2 login in 2 different entities
311
312
		$result = $this->db->query($sql);
313
		if ($result)
314
		{
315
			$obj = $this->db->fetch_object($result);
316
			if ($obj)
317
			{
318
				$this->id 			= $obj->rowid;
319
				$this->ref 			= $obj->rowid;
320
321
				$this->ref_int 		= $obj->ref_int;
322
				$this->ref_ext 		= $obj->ref_ext;
323
324
				$this->ldap_sid 	= $obj->ldap_sid;
325
				$this->lastname		= $obj->lastname;
326
				$this->firstname 	= $obj->firstname;
327
328
				$this->employee		= $obj->employee;
329
330
				$this->login		= $obj->login;
331
				$this->gender       = $obj->gender;
332
				$this->birth        = $this->db->jdate($obj->birth);
333
				$this->pass_indatabase = $obj->pass;
334
				$this->pass_indatabase_crypted = $obj->pass_crypted;
335
				$this->pass			= $obj->pass;
336
				$this->pass_temp	= $obj->pass_temp;
337
				$this->api_key		= $obj->api_key;
338
339
				$this->address 		= $obj->address;
340
				$this->zip 			= $obj->zip;
341
				$this->town 		= $obj->town;
342
343
				$this->country_id = $obj->country_id;
344
				$this->country_code = $obj->country_id?$obj->country_code:'';
345
				//$this->country = $obj->country_id?($langs->trans('Country'.$obj->country_code)!='Country'.$obj->country_code?$langs->transnoentities('Country'.$obj->country_code):$obj->country):'';
346
347
				$this->state_id     = $obj->state_id;
348
				$this->state_code   = $obj->state_code;
349
				$this->state        = ($obj->state!='-'?$obj->state:'');
350
351
				$this->office_phone	= $obj->office_phone;
352
				$this->office_fax   = $obj->office_fax;
353
				$this->user_mobile  = $obj->user_mobile;
354
                $this->personal_mobile = $obj->personal_mobile;
355
				$this->email		= $obj->email;
356
                $this->personal_email = $obj->personal_email;
357
				$this->skype		= $obj->skype;
358
				$this->twitter		= $obj->twitter;
359
				$this->facebook		= $obj->facebook;
360
				$this->linkedin		= $obj->linkedin;
361
				$this->job			= $obj->job;
362
				$this->signature	= $obj->signature;
363
				$this->admin		= $obj->admin;
364
				$this->note			= $obj->note;
365
				$this->statut		= $obj->statut;
366
				$this->photo		= $obj->photo;
367
				$this->openid		= $obj->openid;
368
				$this->lang			= $obj->lang;
369
				$this->entity		= $obj->entity;
370
				$this->accountancy_code = $obj->accountancy_code;
371
				$this->thm			= $obj->thm;
372
				$this->tjm			= $obj->tjm;
373
				$this->salary		= $obj->salary;
374
				$this->salaryextra = $obj->salaryextra;
375
				$this->weeklyhours = $obj->weeklyhours;
376
				$this->color = $obj->color;
377
				$this->dateemployment = $this->db->jdate($obj->dateemployment);
378
				$this->dateemploymentend = $this->db->jdate($obj->dateemploymentend);
379
380
				$this->datec				= $this->db->jdate($obj->datec);
381
				$this->datem				= $this->db->jdate($obj->datem);
382
				$this->datelastlogin		= $this->db->jdate($obj->datel);
383
				$this->datepreviouslogin	= $this->db->jdate($obj->datep);
384
385
				$this->societe_id           = $obj->fk_soc; // deprecated
386
				$this->contact_id           = $obj->fk_socpeople;   // deprecated
387
				$this->socid                = $obj->fk_soc;
388
				$this->contactid            = $obj->fk_socpeople;
389
				$this->fk_member            = $obj->fk_member;
390
				$this->fk_user        		= $obj->fk_user;
391
                $this->fk_user_expense_validator = $obj->fk_user_expense_validator;
392
                $this->fk_user_holiday_validator = $obj->fk_user_holiday_validator;
393
394
				$this->default_range = $obj->default_range;
395
				$this->default_c_exp_tax_cat = $obj->default_c_exp_tax_cat;
396
				$this->fk_warehouse = $obj->fk_warehouse;
397
398
				// Protection when module multicompany was set, admin was set to first entity and then, the module was disabled,
399
				// in such case, this admin user must be admin for ALL entities.
400
				if (empty($conf->multicompany->enabled) && $this->admin && $this->entity == 1) $this->entity = 0;
401
402
				// Retreive all extrafield
403
				// fetch optionals attributes and labels
404
				$this->fetch_optionals();
405
406
				$this->db->free($result);
407
			}
408
			else
409
			{
410
				$this->error="USERNOTFOUND";
411
				dol_syslog(get_class($this)."::fetch user not found", LOG_DEBUG);
412
413
				$this->db->free($result);
414
				return 0;
415
			}
416
		}
417
		else
418
		{
419
			$this->error=$this->db->lasterror();
420
			return -1;
421
		}
422
423
		// To get back the global configuration unique to the user
424
		if ($loadpersonalconf)
425
		{
426
			// Load user->conf for user
427
			$sql = "SELECT param, value FROM ".MAIN_DB_PREFIX."user_param";
428
			$sql.= " WHERE fk_user = ".$this->id;
429
			$sql.= " AND entity = ".$conf->entity;
430
			//dol_syslog(get_class($this).'::fetch load personalized conf', LOG_DEBUG);
431
			$resql=$this->db->query($sql);
432
			if ($resql)
433
			{
434
				$num = $this->db->num_rows($resql);
435
				$i = 0;
436
				while ($i < $num)
437
				{
438
					$obj = $this->db->fetch_object($resql);
439
					$p=(! empty($obj->param)?$obj->param:'');
440
					if (! empty($p)) $this->conf->$p = $obj->value;
441
					$i++;
442
				}
443
				$this->db->free($resql);
444
			}
445
			else
446
			{
447
				$this->error=$this->db->lasterror();
448
				return -2;
449
			}
450
451
			$result = $this->loadDefaultValues();
452
453
			if ($result < 0)
454
			{
455
				$this->error=$this->db->lasterror();
456
				return -3;
457
			}
458
		}
459
460
		return 1;
461
	}
462
463
	/**
464
	 *  Load default value in property ->default_values
465
	 *
466
	 *  @return int						> 0 if OK, < 0 if KO
467
	 */
468
	public function loadDefaultValues()
469
	{
470
		global $conf;
471
472
		// Load user->default_values for user. TODO Save this in memcached ?
473
		$sql = "SELECT rowid, entity, type, page, param, value";
474
		$sql.= " FROM ".MAIN_DB_PREFIX."default_values";
475
		$sql.= " WHERE entity IN (".($this->entity > 0 ? $this->entity.", " : "").$conf->entity.")";	// Entity of user (if defined) + current entity
476
		$sql.= " AND user_id IN (0".($this->id > 0 ? ", ".$this->id : "").")";							// User 0 (all) + me (if defined)
477
		$resql = $this->db->query($sql);
478
		if ($resql)
479
		{
480
			while ($obj = $this->db->fetch_object($resql))
481
			{
482
				if (! empty($obj->page) && ! empty($obj->type) && ! empty($obj->param))
483
				{
484
					// $obj->page is relative URL with or without params
485
					// $obj->type can be 'filters', 'sortorder', 'createform', ...
486
					// $obj->param is key or param
487
					$pagewithoutquerystring=$obj->page;
488
					$pagequeries='';
489
					if (preg_match('/^([^\?]+)\?(.*)$/', $pagewithoutquerystring, $reg))	// There is query param
490
					{
491
						$pagewithoutquerystring=$reg[1];
492
						$pagequeries=$reg[2];
493
					}
494
					$this->default_values[$pagewithoutquerystring][$obj->type][$pagequeries?$pagequeries:'_noquery_'][$obj->param]=$obj->value;
495
					//if ($pagequeries) $this->default_values[$pagewithoutquerystring][$obj->type.'_queries']=$pagequeries;
496
				}
497
			}
498
			// Sort by key, so _noquery_ is last
499
			if(!empty($this->default_values)) {
500
				foreach($this->default_values as $a => $b)
501
				{
502
					foreach($b as $c => $d)
503
					{
504
						krsort($this->default_values[$a][$c]);
505
					}
506
				}
507
			}
508
			$this->db->free($resql);
509
510
			return 1;
511
		}
512
		else
513
		{
514
			dol_print_error($this->db);
515
			return -1;
516
		}
517
	}
518
519
	/**
520
	 *  Add a right to the user
521
	 *
522
	 * 	@param	int		$rid			Id of permission to add or 0 to add several permissions
523
	 *  @param  string	$allmodule		Add all permissions of module $allmodule or 'allmodules' to include all modules.
524
	 *  @param  string	$allperms		Add all permissions of module $allmodule, subperms $allperms only or '' to include all permissions.
525
	 *  @param	int		$entity			Entity to use
526
	 *  @param  int	    $notrigger		1=Does not execute triggers, 0=Execute triggers
527
	 *  @return int						> 0 if OK, < 0 if KO
528
	 *  @see	clearrights(), delrights(), getrights()
529
	 */
530
	public function addrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
531
	{
532
		global $conf, $user, $langs;
533
534
		$entity = (! empty($entity)?$entity:$conf->entity);
535
536
		dol_syslog(get_class($this)."::addrights $rid, $allmodule, $allperms, $entity");
537
		$error=0;
538
		$whereforadd='';
539
540
		$this->db->begin();
541
542
		if (! empty($rid))
543
		{
544
			// Si on a demande ajout d'un droit en particulier, on recupere
545
			// les caracteristiques (module, perms et subperms) de ce droit.
546
			$sql = "SELECT module, perms, subperms";
547
			$sql.= " FROM ".MAIN_DB_PREFIX."rights_def";
548
			$sql.= " WHERE id = '".$this->db->escape($rid)."'";
549
			$sql.= " AND entity = ".$entity;
550
551
			$result=$this->db->query($sql);
552
			if ($result) {
553
				$obj = $this->db->fetch_object($result);
554
				$module=$obj->module;
555
				$perms=$obj->perms;
556
				$subperms=$obj->subperms;
557
			}
558
			else {
559
				$error++;
560
				dol_print_error($this->db);
561
			}
562
563
			// Where pour la liste des droits a ajouter
564
			$whereforadd="id=".$this->db->escape($rid);
565
			// Ajout des droits induits
566
			if (! empty($subperms))   $whereforadd.=" OR (module='$module' AND perms='$perms' AND (subperms='lire' OR subperms='read'))";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $module does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $perms does not seem to be defined for all execution paths leading up to this point.
Loading history...
567
			elseif (! empty($perms)) $whereforadd.=" OR (module='$module' AND (perms='lire' OR perms='read') AND subperms IS NULL)";
568
		}
569
		else {
570
			// On a pas demande un droit en particulier mais une liste de droits
571
			// sur la base d'un nom de module de de perms
572
			// Where pour la liste des droits a ajouter
573
			if (! empty($allmodule))
574
			{
575
				if ($allmodule == 'allmodules')
576
				{
577
					$whereforadd='allmodules';
578
				}
579
				else
580
				{
581
					$whereforadd="module='".$this->db->escape($allmodule)."'";
582
					if (! empty($allperms))  $whereforadd.=" AND perms='".$this->db->escape($allperms)."'";
583
				}
584
			}
585
		}
586
587
		// Ajout des droits trouves grace au critere whereforadd
588
		if (! empty($whereforadd))
589
		{
590
			//print "$module-$perms-$subperms";
591
			$sql = "SELECT id";
592
			$sql.= " FROM ".MAIN_DB_PREFIX."rights_def";
593
			$sql.= " WHERE entity = ".$entity;
594
			if (! empty($whereforadd) && $whereforadd != 'allmodules') {
595
				$sql.= " AND ".$whereforadd;
596
			}
597
598
			$result=$this->db->query($sql);
599
			if ($result)
600
			{
601
				$num = $this->db->num_rows($result);
602
				$i = 0;
603
				while ($i < $num)
604
				{
605
					$obj = $this->db->fetch_object($result);
606
					$nid = $obj->id;
607
608
					$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights WHERE fk_user = ".$this->id." AND fk_id=".$nid." AND entity = ".$entity;
609
					if (! $this->db->query($sql)) $error++;
610
					$sql = "INSERT INTO ".MAIN_DB_PREFIX."user_rights (entity, fk_user, fk_id) VALUES (".$entity.", ".$this->id.", ".$nid.")";
611
					if (! $this->db->query($sql)) $error++;
612
613
					$i++;
614
				}
615
			}
616
			else
617
			{
618
				$error++;
619
				dol_print_error($this->db);
620
			}
621
		}
622
623
		if (! $error && ! $notrigger)
624
		{
625
			$langs->load("other");
626
			$this->context = array('audit'=>$langs->trans("PermissionsAdd").($rid?' (id='.$rid.')':''));
627
628
			// Call trigger
629
			$result=$this->call_trigger('USER_MODIFY', $user);
630
			if ($result < 0) { $error++; }
631
			// End call triggers
632
		}
633
634
		if ($error) {
635
			$this->db->rollback();
636
			return -$error;
637
		}
638
		else {
639
			$this->db->commit();
640
			return 1;
641
		}
642
	}
643
644
645
	/**
646
	 *  Remove a right to the user
647
	 *
648
	 *  @param	int		$rid        Id du droit a retirer
649
	 *  @param  string	$allmodule  Retirer tous les droits du module allmodule
650
	 *  @param  string	$allperms   Retirer tous les droits du module allmodule, perms allperms
651
	 *  @param	int		$entity		Entity to use
652
	 *  @param  int	    $notrigger	1=Does not execute triggers, 0=Execute triggers
653
	 *  @return int         		> 0 if OK, < 0 if OK
654
	 *  @see	clearrights(), addrights(), getrights()
655
	 */
656
	public function delrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
657
	{
658
		global $conf, $user, $langs;
659
660
		$error=0;
661
		$wherefordel='';
662
		$entity = (! empty($entity)?$entity:$conf->entity);
663
664
		$this->db->begin();
665
666
		if (! empty($rid)) {
667
			// Si on a demande supression d'un droit en particulier, on recupere
668
			// les caracteristiques module, perms et subperms de ce droit.
669
			$sql = "SELECT module, perms, subperms";
670
			$sql.= " FROM ".MAIN_DB_PREFIX."rights_def";
671
			$sql.= " WHERE id = '".$this->db->escape($rid)."'";
672
			$sql.= " AND entity = ".$entity;
673
674
			$result=$this->db->query($sql);
675
			if ($result) {
676
				$obj = $this->db->fetch_object($result);
677
				$module=$obj->module;
678
				$perms=$obj->perms;
679
				$subperms=$obj->subperms;
680
			}
681
			else {
682
				$error++;
683
				dol_print_error($this->db);
684
			}
685
686
			// Where pour la liste des droits a supprimer
687
			$wherefordel="id=".$this->db->escape($rid);
688
			// Suppression des droits induits
689
			if ($subperms=='lire' || $subperms=='read') $wherefordel.=" OR (module='$module' AND perms='$perms' AND subperms IS NOT NULL)";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $module does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $subperms does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $perms does not seem to be defined for all execution paths leading up to this point.
Loading history...
690
			if ($perms=='lire' || $perms=='read')       $wherefordel.=" OR (module='$module')";
691
		} else {
692
			// On a demande suppression d'un droit sur la base d'un nom de module ou perms
693
			// Where pour la liste des droits a supprimer
694
			if (! empty($allmodule))
695
			{
696
				if ($allmodule == 'allmodules')
697
				{
698
					$wherefordel='allmodules';
699
				}
700
				else
701
				{
702
					$wherefordel="module='".$this->db->escape($allmodule)."'";
703
					if (! empty($allperms))  $whereforadd.=" AND perms='".$this->db->escape($allperms)."'";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $whereforadd does not exist. Did you maybe mean $wherefordel?
Loading history...
704
				}
705
			}
706
		}
707
708
		// Suppression des droits selon critere defini dans wherefordel
709
		if (! empty($wherefordel))
710
		{
711
			//print "$module-$perms-$subperms";
712
			$sql = "SELECT id";
713
			$sql.= " FROM ".MAIN_DB_PREFIX."rights_def";
714
			$sql.= " WHERE entity = ".$entity;
715
			if (! empty($wherefordel) && $wherefordel != 'allmodules') {
716
				$sql.= " AND ".$wherefordel;
717
			}
718
719
			$result=$this->db->query($sql);
720
			if ($result)
721
			{
722
				$num = $this->db->num_rows($result);
723
				$i = 0;
724
				while ($i < $num)
725
				{
726
					$obj = $this->db->fetch_object($result);
727
					$nid = $obj->id;
728
729
					$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights";
730
					$sql.= " WHERE fk_user = ".$this->id." AND fk_id=".$nid;
731
					$sql.= " AND entity = ".$entity;
732
					if (! $this->db->query($sql)) $error++;
733
734
					$i++;
735
				}
736
			}
737
			else
738
			{
739
				$error++;
740
				dol_print_error($this->db);
741
			}
742
		}
743
744
		if (! $error && ! $notrigger)
745
		{
746
			$langs->load("other");
747
			$this->context = array('audit'=>$langs->trans("PermissionsDelete").($rid?' (id='.$rid.')':''));
748
749
			// Call trigger
750
			$result=$this->call_trigger('USER_MODIFY', $user);
751
			if ($result < 0) { $error++; }
752
			// End call triggers
753
		}
754
755
		if ($error) {
756
			$this->db->rollback();
757
			return -$error;
758
		}
759
		else {
760
			$this->db->commit();
761
			return 1;
762
		}
763
	}
764
765
766
	/**
767
	 *  Clear all permissions array of user
768
	 *
769
	 *  @return	void
770
	 *  @see	getrights()
771
	 */
772
	public function clearrights()
773
	{
774
		dol_syslog(get_class($this)."::clearrights reset user->rights");
775
		$this->rights='';
776
		$this->nb_rights=0;
777
		$this->all_permissions_are_loaded=0;
778
		$this->_tab_loaded=array();
779
	}
780
781
782
	/**
783
	 *	Load permissions granted to user into object user
784
	 *
785
	 *	@param  string	$moduletag		Limit permission for a particular module ('' by default means load all permissions)
786
	 *  @param	int		$forcereload	Force reload of permissions even if they were already loaded (ignore cache)
787
	 *	@return	void
788
	 *  @see	clearrights(), delrights(), addrights()
789
	 */
790
	public function getrights($moduletag = '', $forcereload = 0)
791
	{
792
		global $conf;
793
794
		if (empty($forcereload))
795
		{
796
			if ($moduletag && isset($this->_tab_loaded[$moduletag]) && $this->_tab_loaded[$moduletag])
797
			{
798
				// Rights for this module are already loaded, so we leave
799
				return;
800
			}
801
802
			if (! empty($this->all_permissions_are_loaded))
803
			{
804
				// We already loaded all rights for this user, so we leave
805
				return;
806
			}
807
		}
808
809
		// Get permission of users + Get permissions of groups
810
811
		// First user permissions
812
		$sql = "SELECT DISTINCT r.module, r.perms, r.subperms";
813
		$sql.= " FROM ".MAIN_DB_PREFIX."user_rights as ur";
814
		$sql.= ", ".MAIN_DB_PREFIX."rights_def as r";
815
		$sql.= " WHERE r.id = ur.fk_id";
816
		if (! empty($conf->global->MULTICOMPANY_BACKWARD_COMPATIBILITY))
817
		{
818
			$sql.= " AND r.entity IN (0,".(! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)?"1,":"").$conf->entity.")";
819
		}
820
		else
821
		{
822
			$sql.= " AND ur.entity = ".$conf->entity;
823
		}
824
		$sql.= " AND ur.fk_user= ".$this->id;
825
		$sql.= " AND r.perms IS NOT NULL";
826
		if ($moduletag) $sql.= " AND r.module = '".$this->db->escape($moduletag)."'";
827
828
		$resql = $this->db->query($sql);
829
		if ($resql)
830
		{
831
			$num = $this->db->num_rows($resql);
832
			$i = 0;
833
			while ($i < $num)
834
			{
835
				$obj = $this->db->fetch_object($resql);
836
837
				$module=$obj->module;
838
				$perms=$obj->perms;
839
				$subperms=$obj->subperms;
840
841
				if ($perms)
842
				{
843
					if (! isset($this->rights) || ! is_object($this->rights)) $this->rights = new stdClass(); // For avoid error
844
					if ($module)
845
					{
846
						if (! isset($this->rights->$module) || ! is_object($this->rights->$module)) $this->rights->$module = new stdClass();
847
						if ($subperms)
848
						{
849
							if (! isset($this->rights->$module->$perms) || ! is_object($this->rights->$module->$perms)) $this->rights->$module->$perms = new stdClass();
850
							if(empty($this->rights->$module->$perms->$subperms)) $this->nb_rights++;
851
							$this->rights->$module->$perms->$subperms = 1;
852
						}
853
						else
854
						{
855
							if(empty($this->rights->$module->$perms)) $this->nb_rights++;
856
							$this->rights->$module->$perms = 1;
857
						}
858
					}
859
				}
860
				$i++;
861
			}
862
			$this->db->free($resql);
863
		}
864
865
		// Now permissions of groups
866
		$sql = "SELECT DISTINCT r.module, r.perms, r.subperms";
867
		$sql.= " FROM ".MAIN_DB_PREFIX."usergroup_rights as gr,";
868
		$sql.= " ".MAIN_DB_PREFIX."usergroup_user as gu,";
869
		$sql.= " ".MAIN_DB_PREFIX."rights_def as r";
870
		$sql.= " WHERE r.id = gr.fk_id";
871
		if (! empty($conf->global->MULTICOMPANY_BACKWARD_COMPATIBILITY))
872
		{
873
			if (! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
874
				$sql.= " AND gu.entity IN (0,".$conf->entity.")";
875
			} else {
876
				$sql.= " AND r.entity = ".$conf->entity;
877
			}
878
		}
879
		else
880
		{
881
			$sql.= " AND gr.entity = ".$conf->entity;
882
			$sql.= " AND r.entity = ".$conf->entity;
883
		}
884
		$sql.= " AND gr.fk_usergroup = gu.fk_usergroup";
885
		$sql.= " AND gu.fk_user = ".$this->id;
886
		$sql.= " AND r.perms IS NOT NULL";
887
		if ($moduletag) $sql.= " AND r.module = '".$this->db->escape($moduletag)."'";
888
889
		$resql = $this->db->query($sql);
890
		if ($resql)
891
		{
892
			$num = $this->db->num_rows($resql);
893
			$i = 0;
894
			while ($i < $num)
895
			{
896
				$obj = $this->db->fetch_object($resql);
897
898
				$module=$obj->module;
899
				$perms=$obj->perms;
900
				$subperms=$obj->subperms;
901
902
				if ($perms)
903
				{
904
					if (! isset($this->rights) || ! is_object($this->rights)) $this->rights = new stdClass(); // For avoid error
905
					if (! isset($this->rights->$module) || ! is_object($this->rights->$module)) $this->rights->$module = new stdClass();
906
					if ($subperms)
907
					{
908
						if (! isset($this->rights->$module->$perms) || ! is_object($this->rights->$module->$perms)) $this->rights->$module->$perms = new stdClass();
909
						if(empty($this->rights->$module->$perms->$subperms)) $this->nb_rights++;
910
						$this->rights->$module->$perms->$subperms = 1;
911
					}
912
					else
913
					{
914
						if(empty($this->rights->$module->$perms)) $this->nb_rights++;
915
						// 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
916
						if (!is_object($this->rights->$module->$perms)) $this->rights->$module->$perms = 1;
917
					}
918
				}
919
				$i++;
920
			}
921
			$this->db->free($resql);
922
		}
923
924
		// For backward compatibility
925
		if (isset($this->rights->propale) && ! isset($this->rights->propal)) $this->rights->propal = $this->rights->propale;
926
		if (isset($this->rights->propal) && ! isset($this->rights->propale)) $this->rights->propale = $this->rights->propal;
927
928
		if (! $moduletag)
929
		{
930
			// Si module etait non defini, alors on a tout charge, on peut donc considerer
931
			// que les droits sont en cache (car tous charges) pour cet instance de user
932
			$this->all_permissions_are_loaded=1;
933
		}
934
		else
935
		{
936
			// If module defined, we flag it as loaded into cache
937
			$this->_tab_loaded[$moduletag]=1;
938
		}
939
	}
940
941
	/**
942
	 *  Change status of a user
943
	 *
944
	 *	@param	int		$statut		Status to set
945
	 *  @return int     			<0 if KO, 0 if nothing is done, >0 if OK
946
	 */
947
	public function setstatus($statut)
948
	{
949
		global $conf,$langs,$user;
950
951
		$error=0;
952
953
		// Check parameters
954
		if ($this->statut == $statut) return 0;
955
		else $this->statut = $statut;
956
957
		$this->db->begin();
958
959
		// Deactivate user
960
		$sql = "UPDATE ".MAIN_DB_PREFIX."user";
961
		$sql.= " SET statut = ".$this->statut;
962
		$sql.= " WHERE rowid = ".$this->id;
963
		$result = $this->db->query($sql);
964
965
		dol_syslog(get_class($this)."::setstatus", LOG_DEBUG);
966
		if ($result)
967
		{
968
			// Call trigger
969
			$result=$this->call_trigger('USER_ENABLEDISABLE', $user);
970
			if ($result < 0) { $error++; }
971
			// End call triggers
972
		}
973
974
		if ($error)
975
		{
976
			$this->db->rollback();
977
			return -$error;
978
		}
979
		else
980
		{
981
			$this->db->commit();
982
			return 1;
983
		}
984
	}
985
986
	/**
987
	 * Sets object to supplied categories.
988
	 *
989
	 * Deletes object from existing categories not supplied.
990
	 * Adds it to non existing supplied categories.
991
	 * Existing categories are left untouch.
992
	 *
993
	 * @param int[]|int $categories Category or categories IDs
994
     * @return void
995
	 */
996
	public function setCategories($categories)
997
	{
998
		// Handle single category
999
		if (!is_array($categories)) {
1000
			$categories = array($categories);
1001
		}
1002
1003
		// Get current categories
1004
		require_once DOL_DOCUMENT_ROOT . '/categories/class/categorie.class.php';
1005
		$c = new Categorie($this->db);
1006
		$existing = $c->containing($this->id, Categorie::TYPE_USER, 'id');
1007
1008
		// Diff
1009
		if (is_array($existing)) {
0 ignored issues
show
introduced by
The condition is_array($existing) is always false.
Loading history...
1010
			$to_del = array_diff($existing, $categories);
1011
			$to_add = array_diff($categories, $existing);
1012
		} else {
1013
			$to_del = array(); // Nothing to delete
1014
			$to_add = $categories;
1015
		}
1016
1017
		// Process
1018
		foreach ($to_del as $del) {
1019
			if ($c->fetch($del) > 0) {
1020
				$c->del_type($this, 'user');
1021
			}
1022
		}
1023
		foreach ($to_add as $add) {
1024
			if ($c->fetch($add) > 0) {
1025
				$c->add_type($this, 'user');
1026
			}
1027
		}
1028
1029
		return;
1030
	}
1031
1032
	/**
1033
	 *  Delete the user
1034
	 *
1035
	 *	@param		User	$user	User than delete
1036
	 * 	@return		int				<0 if KO, >0 if OK
1037
	 */
1038
	public function delete(User $user)
1039
	{
1040
		global $conf,$langs;
1041
1042
		$error=0;
1043
1044
		$this->db->begin();
1045
1046
		$this->fetch($this->id);
1047
1048
		dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1049
1050
		// Remove rights
1051
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights WHERE fk_user = ".$this->id;
1052
1053
		if (! $error && ! $this->db->query($sql))
1054
		{
1055
			$error++;
1056
			$this->error = $this->db->lasterror();
1057
		}
1058
1059
		// Remove group
1060
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."usergroup_user WHERE fk_user  = ".$this->id;
1061
		if (! $error && ! $this->db->query($sql))
1062
		{
1063
			$error++;
1064
			$this->error = $this->db->lasterror();
1065
		}
1066
1067
		// If contact, remove link
1068
		if ($this->contact_id)
1 ignored issue
show
Deprecated Code introduced by
The property User::$contact_id has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1068
		if (/** @scrutinizer ignore-deprecated */ $this->contact_id)
Loading history...
1069
		{
1070
			$sql = "UPDATE ".MAIN_DB_PREFIX."socpeople SET fk_user_creat = null WHERE rowid = ".$this->contact_id;
1 ignored issue
show
Deprecated Code introduced by
The property User::$contact_id has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1070
			$sql = "UPDATE ".MAIN_DB_PREFIX."socpeople SET fk_user_creat = null WHERE rowid = "./** @scrutinizer ignore-deprecated */ $this->contact_id;
Loading history...
1071
			if (! $error && ! $this->db->query($sql))
1072
			{
1073
				$error++;
1074
				$this->error = $this->db->lasterror();
1075
			}
1076
		}
1077
1078
		// Remove extrafields
1079
		if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
1080
		{
1081
		    $result=$this->deleteExtraFields();
1082
		    if ($result < 0)
1083
		    {
1084
		        $error++;
1085
		        dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1086
		    }
1087
		}
1088
1089
		// Remove user
1090
		if (! $error)
1091
		{
1092
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".$this->id;
1093
		   	dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1094
		   	if (! $this->db->query($sql))
1095
		   	{
1096
		   		$error++;
1097
		   		$this->error = $this->db->lasterror();
1098
		   	}
1099
		}
1100
1101
		if (! $error)
1102
		{
1103
			// Call trigger
1104
			$result=$this->call_trigger('USER_DELETE', $user);
1105
			if ($result < 0)
1106
			{
1107
				$error++;
1108
				$this->db->rollback();
1109
				return -1;
1110
			}
1111
			// End call triggers
1112
1113
			$this->db->commit();
1114
			return 1;
1115
		}
1116
		else
1117
		{
1118
			$this->db->rollback();
1119
			return -1;
1120
		}
1121
	}
1122
1123
	/**
1124
	 *  Create a user into database
1125
	 *
1126
	 *  @param	User	$user        	Objet user doing creation
1127
	 *  @param  int		$notrigger		1=do not execute triggers, 0 otherwise
1128
	 *  @return int			         	<0 if KO, id of created user if OK
1129
	 */
1130
	public function create($user, $notrigger = 0)
1131
	{
1132
		global $conf,$langs;
1133
		global $mysoc;
1134
1135
		// Clean parameters
1136
		$this->login = trim($this->login);
1137
		if (! isset($this->entity)) $this->entity=$conf->entity;	// If not defined, we use default value
1138
1139
		dol_syslog(get_class($this)."::create login=".$this->login.", user=".(is_object($user)?$user->id:''), LOG_DEBUG);
1140
1141
		// Check parameters
1142
		if (! empty($conf->global->USER_MAIL_REQUIRED) && ! isValidEMail($this->email))
1143
		{
1144
			$langs->load("errors");
1145
			$this->error = $langs->trans("ErrorBadEMail", $this->email);
1146
			return -1;
1147
		}
1148
		if (empty($this->login))
1149
		{
1150
			$langs->load("errors");
1151
			$this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Login"));
1152
			return -1;
1153
		}
1154
1155
		$this->datec = dol_now();
1156
1157
		$error=0;
1158
		$this->db->begin();
1159
1160
		$sql = "SELECT login FROM ".MAIN_DB_PREFIX."user";
1161
		$sql.= " WHERE login ='".$this->db->escape($this->login)."'";
1162
		$sql.= " AND entity IN (0,".$this->db->escape($conf->entity).")";
1163
1164
		dol_syslog(get_class($this)."::create", LOG_DEBUG);
1165
		$resql=$this->db->query($sql);
1166
		if ($resql)
1167
		{
1168
			$num = $this->db->num_rows($resql);
1169
			$this->db->free($resql);
1170
1171
			if ($num)
1172
			{
1173
				$this->error = 'ErrorLoginAlreadyExists';
1174
				dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
1175
				$this->db->rollback();
1176
				return -6;
1177
			}
1178
			else
1179
			{
1180
				$sql = "INSERT INTO ".MAIN_DB_PREFIX."user (datec,login,ldap_sid,entity)";
1181
				$sql.= " VALUES('".$this->db->idate($this->datec)."','".$this->db->escape($this->login)."','".$this->db->escape($this->ldap_sid)."',".$this->db->escape($this->entity).")";
1182
				$result=$this->db->query($sql);
1183
1184
				dol_syslog(get_class($this)."::create", LOG_DEBUG);
1185
				if ($result)
1186
				{
1187
					$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."user");
1188
1189
					// Set default rights
1190
					if ($this->set_default_rights() < 0)
1191
					{
1192
						$this->error='ErrorFailedToSetDefaultRightOfUser';
1193
						$this->db->rollback();
1194
						return -5;
1195
					}
1196
1197
					// Update minor fields
1198
					$result = $this->update($user, 1, 1);
1199
					if ($result < 0)
1200
					{
1201
						$this->db->rollback();
1202
						return -4;
1203
					}
1204
1205
					if (! empty($conf->global->STOCK_USERSTOCK_AUTOCREATE))
1206
					{
1207
						require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
1208
						$langs->load("stocks");
1209
						$entrepot = new Entrepot($this->db);
1210
						$entrepot->libelle = $langs->trans("PersonalStock", $this->getFullName($langs));
1211
						$entrepot->description = $langs->trans("ThisWarehouseIsPersonalStock", $this->getFullName($langs));
1212
						$entrepot->statut = 1;
1213
						$entrepot->country_id = $mysoc->country_id;
1214
						$entrepot->create($user);
1215
					}
1216
1217
					if (! $notrigger)
1218
					{
1219
						// Call trigger
1220
						$result=$this->call_trigger('USER_CREATE', $user);
1221
						if ($result < 0) { $error++; }
1222
						// End call triggers
1223
					}
1224
1225
					if (! $error)
1226
					{
1227
						$this->db->commit();
1228
						return $this->id;
1229
					}
1230
					else
1231
					{
1232
						//$this->error=$interface->error;
1233
						dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
1234
						$this->db->rollback();
1235
						return -3;
1236
					}
1237
				}
1238
				else
1239
				{
1240
					$this->error=$this->db->lasterror();
1241
					$this->db->rollback();
1242
					return -2;
1243
				}
1244
			}
1245
		}
1246
		else
1247
		{
1248
			$this->error=$this->db->lasterror();
1249
			$this->db->rollback();
1250
			return -1;
1251
		}
1252
	}
1253
1254
1255
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1256
	/**
1257
	 *  Create a user from a contact object. User will be internal but if contact is linked to a third party, user will be external
1258
	 *
1259
	 *  @param	Contact	$contact    Object for source contact
1260
	 * 	@param  string	$login      Login to force
1261
	 *  @param  string	$password   Password to force
1262
	 *  @return int 				<0 if error, if OK returns id of created user
1263
	 */
1264
	public function create_from_contact($contact, $login = '', $password = '')
1265
	{
1266
        // phpcs:enable
1267
		global $conf,$user,$langs;
1268
1269
		$error=0;
1270
1271
		// Define parameters
1272
		$this->admin = 0;
1273
		$this->lastname = $contact->lastname;
1274
		$this->firstname = $contact->firstname;
1275
		$this->gender = $contact->gender;
1276
		$this->email = $contact->email;
1277
		$this->skype = $contact->skype;
1278
		$this->twitter = $contact->twitter;
1279
		$this->facebook = $contact->facebook;
1280
		$this->linkedin = $contact->linkedin;
1281
		$this->office_phone = $contact->phone_pro;
1282
		$this->office_fax = $contact->fax;
1283
		$this->user_mobile = $contact->phone_mobile;
1284
		$this->address = $contact->address;
1285
		$this->zip = $contact->zip;
1286
		$this->town = $contact->town;
1287
		$this->state_id = $contact->state_id;
1288
		$this->country_id = $contact->country_id;
1289
		$this->employee = 0;
1290
1291
		if (empty($login)) $login=strtolower(substr($contact->firstname, 0, 4)) . strtolower(substr($contact->lastname, 0, 4));
1292
		$this->login = $login;
1293
1294
		$this->db->begin();
1295
1296
		// Cree et positionne $this->id
1297
		$result=$this->create($user);
1298
		if ($result > 0)
1299
		{
1300
			$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1301
			$sql.= " SET fk_socpeople=".$contact->id;
1302
			if ($contact->socid) $sql.=", fk_soc=".$contact->socid;
1303
			$sql.= " WHERE rowid=".$this->id;
1304
			$resql=$this->db->query($sql);
1305
1306
			dol_syslog(get_class($this)."::create_from_contact", LOG_DEBUG);
1307
			if ($resql)
1308
			{
1309
				$this->context['createfromcontact']='createfromcontact';
1310
1311
				// Call trigger
1312
				$result=$this->call_trigger('USER_CREATE', $user);
1313
				if ($result < 0) { $error++; $this->db->rollback(); return -1; }
1314
				// End call triggers
1315
1316
				$this->db->commit();
1317
				return $this->id;
1318
			}
1319
			else
1320
			{
1321
				$this->error=$this->db->error();
1322
1323
				$this->db->rollback();
1324
				return -1;
1325
			}
1326
		}
1327
		else
1328
		{
1329
			// $this->error deja positionne
1330
			dol_syslog(get_class($this)."::create_from_contact - 0");
1331
1332
			$this->db->rollback();
1333
			return $result;
1334
		}
1335
	}
1336
1337
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1338
	/**
1339
	 *  Create a user into database from a member object
1340
	 *
1341
	 *  @param	Adherent	$member		Object member source
1342
	 * 	@param	string		$login		Login to force
1343
	 *  @return int						<0 if KO, if OK, return id of created account
1344
	 */
1345
	public function create_from_member($member, $login = '')
1346
	{
1347
        // phpcs:enable
1348
		global $conf,$user,$langs;
1349
1350
		// Positionne parametres
1351
		$this->admin = 0;
1352
		$this->lastname     = $member->lastname;
1353
		$this->firstname    = $member->firstname;
1354
		$this->gender		= $member->gender;
1355
		$this->email        = $member->email;
1356
		$this->fk_member    = $member->id;
1357
		$this->pass         = $member->pass;
1358
		$this->address      = $member->address;
1359
		$this->zip          = $member->zip;
1360
		$this->town         = $member->town;
1361
		$this->state_id     = $member->state_id;
1362
		$this->country_id   = $member->country_id;
1363
1364
		if (empty($login)) $login=strtolower(substr($member->firstname, 0, 4)) . strtolower(substr($member->lastname, 0, 4));
1365
		$this->login = $login;
1366
1367
		$this->db->begin();
1368
1369
		// Create and set $this->id
1370
		$result=$this->create($user);
1371
		if ($result > 0)
1372
		{
1373
			$newpass=$this->setPassword($user, $this->pass);
1374
			if (is_numeric($newpass) && $newpass < 0) $result=-2;
1375
1376
			if ($result > 0 && $member->fk_soc)	// If member is linked to a thirdparty
1377
			{
1378
				$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1379
				$sql.= " SET fk_soc=".$member->fk_soc;
1380
				$sql.= " WHERE rowid=".$this->id;
1381
1382
				dol_syslog(get_class($this)."::create_from_member", LOG_DEBUG);
1383
				$resql=$this->db->query($sql);
1384
				if ($resql)
1385
				{
1386
					$this->db->commit();
1387
					return $this->id;
1388
				}
1389
				else
1390
				{
1391
					$this->error=$this->db->lasterror();
1392
1393
					$this->db->rollback();
1394
					return -1;
1395
				}
1396
			}
1397
		}
1398
1399
		if ($result > 0)
1400
		{
1401
			$this->db->commit();
1402
			return $this->id;
1403
		}
1404
		else
1405
		{
1406
			// $this->error deja positionne
1407
			$this->db->rollback();
1408
			return -2;
1409
		}
1410
	}
1411
1412
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1413
	/**
1414
	 *    Assign rights by default
1415
	 *
1416
	 *    @return     integer erreur <0, si ok renvoi le nbre de droits par defaut positionnes
1417
	 */
1418
	public function set_default_rights()
1419
	{
1420
        // phpcs:enable
1421
		global $conf;
1422
1423
		$sql = "SELECT id FROM ".MAIN_DB_PREFIX."rights_def";
1424
		$sql.= " WHERE bydefault = 1";
1425
		$sql.= " AND entity = ".$conf->entity;
1426
1427
		$resql=$this->db->query($sql);
1428
		if ($resql)
1429
		{
1430
			$num = $this->db->num_rows($resql);
1431
			$i = 0;
1432
			$rd = array();
1433
			while ($i < $num)
1434
			{
1435
				$row = $this->db->fetch_row($resql);
1436
				$rd[$i] = $row[0];
1437
				$i++;
1438
			}
1439
			$this->db->free($resql);
1440
		}
1441
		$i = 0;
1442
		while ($i < $num)
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $num does not seem to be defined for all execution paths leading up to this point.
Loading history...
1443
		{
1444
1445
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights WHERE fk_user = $this->id AND fk_id=$rd[$i]";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rd does not seem to be defined for all execution paths leading up to this point.
Loading history...
1446
			$result=$this->db->query($sql);
1447
1448
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."user_rights (fk_user, fk_id) VALUES ($this->id, $rd[$i])";
1449
			$result=$this->db->query($sql);
1450
			if (! $result) return -1;
1451
			$i++;
1452
		}
1453
1454
		return $i;
1455
	}
1456
1457
	/**
1458
	 *  	Update a user into database (and also password if this->pass is defined)
1459
	 *
1460
	 *		@param	User	$user				User qui fait la mise a jour
1461
	 *    	@param  int		$notrigger			1 ne declenche pas les triggers, 0 sinon
1462
	 *		@param	int		$nosyncmember		0=Synchronize linked member (standard info), 1=Do not synchronize linked member
1463
	 *		@param	int		$nosyncmemberpass	0=Synchronize linked member (password), 1=Do not synchronize linked member
1464
	 *		@param	int		$nosynccontact		0=Synchronize linked contact, 1=Do not synchronize linked contact
1465
	 *    	@return int 		        		<0 si KO, >=0 si OK
1466
	 */
1467
	public function update($user, $notrigger = 0, $nosyncmember = 0, $nosyncmemberpass = 0, $nosynccontact = 0)
1468
	{
1469
		global $conf, $langs;
1470
1471
		$nbrowsaffected=0;
1472
		$error=0;
1473
1474
		dol_syslog(get_class($this)."::update notrigger=".$notrigger.", nosyncmember=".$nosyncmember.", nosyncmemberpass=".$nosyncmemberpass);
1475
1476
		// Clean parameters
1477
		$this->lastname     = trim($this->lastname);
1478
		$this->firstname    = trim($this->firstname);
1479
		$this->employee    	= $this->employee?$this->employee:0;
1480
		$this->login        = trim($this->login);
1481
		$this->gender       = trim($this->gender);
1482
		$this->birth        = trim($this->birth);
1483
		$this->pass         = trim($this->pass);
1484
		$this->api_key      = trim($this->api_key);
1485
		$this->address		= $this->address?trim($this->address):trim($this->address);
1486
		$this->zip			= $this->zip?trim($this->zip):trim($this->zip);
1487
		$this->town			= $this->town?trim($this->town):trim($this->town);
1488
		$this->state_id		= trim($this->state_id);
1489
		$this->country_id	= ($this->country_id > 0)?$this->country_id:0;
1490
		$this->office_phone = trim($this->office_phone);
1491
		$this->office_fax   = trim($this->office_fax);
1492
		$this->user_mobile  = trim($this->user_mobile);
1493
        $this->personal_mobile  = trim($this->personal_mobile);
1494
		$this->email        = trim($this->email);
1495
        $this->personal_email = trim($this->personal_email);
1496
1497
		$this->skype        = trim($this->skype);
1498
		$this->twitter      = trim($this->twitter);
1499
		$this->facebook     = trim($this->facebook);
1500
		$this->linkedin     = trim($this->linkedin);
1501
1502
		$this->job    		= trim($this->job);
1503
		$this->signature    = trim($this->signature);
1504
		$this->note         = trim($this->note);
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$note has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1504
		/** @scrutinizer ignore-deprecated */ $this->note         = trim($this->note);
Loading history...
1505
		$this->openid       = trim(empty($this->openid)?'':$this->openid);    // Avoid warning
1506
		$this->admin        = $this->admin?$this->admin:0;
1507
		$this->address		= empty($this->address)?'':$this->address;
1508
		$this->zip			= empty($this->zip)?'':$this->zip;
1509
		$this->town			= empty($this->town)?'':$this->town;
1510
		$this->accountancy_code = trim($this->accountancy_code);
1511
		$this->color = empty($this->color)?'':$this->color;
1512
		$this->dateemployment = empty($this->dateemployment)?'':$this->dateemployment;
1513
		$this->dateemploymentend = empty($this->dateemploymentend)?'':$this->dateemploymentend;
1514
		$this->fk_warehouse = trim(empty($this->fk_warehouse)?'':$this->fk_warehouse);
1515
1516
		// Check parameters
1517
		if (! empty($conf->global->USER_MAIL_REQUIRED) && ! isValidEMail($this->email))
1518
		{
1519
			$langs->load("errors");
1520
			$this->error = $langs->trans("ErrorBadEMail", $this->email);
1521
			return -1;
1522
		}
1523
		if (empty($this->login))
1524
		{
1525
			$langs->load("errors");
1526
			$this->error = $langs->trans("ErrorFieldRequired", $this->login);
1527
			return -1;
1528
		}
1529
1530
		$this->db->begin();
1531
1532
		// Update datas
1533
		$sql = "UPDATE ".MAIN_DB_PREFIX."user SET";
1534
		$sql.= " lastname = '".$this->db->escape($this->lastname)."'";
1535
		$sql.= ", firstname = '".$this->db->escape($this->firstname)."'";
1536
		$sql.= ", employee = ".(int) $this->employee;
1537
		$sql.= ", login = '".$this->db->escape($this->login)."'";
1538
		$sql.= ", api_key = ".($this->api_key ? "'".$this->db->escape($this->api_key)."'" : "null");
1539
		$sql.= ", gender = ".($this->gender != -1 ? "'".$this->db->escape($this->gender)."'" : "null");	// 'man' or 'woman'
1540
		$sql.= ", birth=".(strval($this->birth)!='' ? "'".$this->db->idate($this->birth)."'" : 'null');
1541
		if (! empty($user->admin)) $sql.= ", admin = ".(int) $this->admin;	// admin flag can be set/unset only by an admin user
1542
		$sql.= ", address = '".$this->db->escape($this->address)."'";
1543
		$sql.= ", zip = '".$this->db->escape($this->zip)."'";
1544
		$sql.= ", town = '".$this->db->escape($this->town)."'";
1545
		$sql.= ", fk_state = ".((! empty($this->state_id) && $this->state_id > 0)?"'".$this->db->escape($this->state_id)."'":"null");
1546
		$sql.= ", fk_country = ".((! empty($this->country_id) && $this->country_id > 0)?"'".$this->db->escape($this->country_id)."'":"null");
1547
		$sql.= ", office_phone = '".$this->db->escape($this->office_phone)."'";
1548
		$sql.= ", office_fax = '".$this->db->escape($this->office_fax)."'";
1549
		$sql.= ", user_mobile = '".$this->db->escape($this->user_mobile)."'";
1550
        $sql.= ", personal_mobile = '".$this->db->escape($this->personal_mobile)."'";
1551
		$sql.= ", email = '".$this->db->escape($this->email)."'";
1552
        $sql.= ", personal_email = '".$this->db->escape($this->personal_email)."'";
1553
		$sql.= ", skype = '".$this->db->escape($this->skype)."'";
1554
		$sql.= ", twitter = '".$this->db->escape($this->twitter)."'";
1555
		$sql.= ", facebook = '".$this->db->escape($this->facebook)."'";
1556
		$sql.= ", linkedin = '".$this->db->escape($this->linkedin)."'";
1557
		$sql.= ", job = '".$this->db->escape($this->job)."'";
1558
		$sql.= ", signature = '".$this->db->escape($this->signature)."'";
1559
		$sql.= ", accountancy_code = '".$this->db->escape($this->accountancy_code)."'";
1560
		$sql.= ", color = '".$this->db->escape($this->color)."'";
1561
		$sql.= ", dateemployment=".(strval($this->dateemployment)!='' ? "'".$this->db->idate($this->dateemployment)."'" : 'null');
1562
		$sql.= ", dateemploymentend=".(strval($this->dateemploymentend)!='' ? "'".$this->db->idate($this->dateemploymentend)."'" : 'null');
1563
		$sql.= ", note = '".$this->db->escape($this->note)."'";
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$note has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

1563
		$sql.= ", note = '".$this->db->escape(/** @scrutinizer ignore-deprecated */ $this->note)."'";
Loading history...
1564
		$sql.= ", photo = ".($this->photo?"'".$this->db->escape($this->photo)."'":"null");
1565
		$sql.= ", openid = ".($this->openid?"'".$this->db->escape($this->openid)."'":"null");
1566
		$sql.= ", fk_user = ".($this->fk_user > 0?"'".$this->db->escape($this->fk_user)."'":"null");
1567
        $sql.= ", fk_user_expense_validator = ".($this->fk_user_expense_validator > 0?"'".$this->db->escape($this->fk_user_expense_validator)."'":"null");
1568
        $sql.= ", fk_user_holiday_validator = ".($this->fk_user_holiday_validator > 0?"'".$this->db->escape($this->fk_user_holiday_validator)."'":"null");
1569
		if (isset($this->thm) || $this->thm != '')                 $sql.= ", thm= ".($this->thm != ''?"'".$this->db->escape($this->thm)."'":"null");
1570
		if (isset($this->tjm) || $this->tjm != '')                 $sql.= ", tjm= ".($this->tjm != ''?"'".$this->db->escape($this->tjm)."'":"null");
1571
		if (isset($this->salary) || $this->salary != '')           $sql.= ", salary= ".($this->salary != ''?"'".$this->db->escape($this->salary)."'":"null");
1572
		if (isset($this->salaryextra) || $this->salaryextra != '') $sql.= ", salaryextra= ".($this->salaryextra != ''?"'".$this->db->escape($this->salaryextra)."'":"null");
1573
		$sql.= ", weeklyhours= ".($this->weeklyhours != ''?"'".$this->db->escape($this->weeklyhours)."'":"null");
1574
		$sql.= ", entity = '".$this->db->escape($this->entity)."'";
1575
		$sql.= ", default_range = ".($this->default_range > 0 ? $this->default_range : 'null');
1576
		$sql.= ", default_c_exp_tax_cat = ".($this->default_c_exp_tax_cat > 0 ? $this->default_c_exp_tax_cat : 'null');
1577
		$sql.= ", fk_warehouse = ".($this->fk_warehouse?"'".$this->db->escape($this->fk_warehouse)."'":"null");
1578
1579
		$sql.= " WHERE rowid = ".$this->id;
1580
1581
		dol_syslog(get_class($this)."::update", LOG_DEBUG);
1582
		$resql = $this->db->query($sql);
1583
		if ($resql)
1584
		{
1585
			$nbrowsaffected+=$this->db->affected_rows($resql);
1586
1587
			// Update password
1588
			if (!empty($this->pass))
1589
			{
1590
				if ($this->pass != $this->pass_indatabase && $this->pass != $this->pass_indatabase_crypted)
1591
				{
1592
					// Si mot de passe saisi et different de celui en base
1593
					$result=$this->setPassword($user, $this->pass, 0, $notrigger, $nosyncmemberpass);
1594
					if (! $nbrowsaffected) $nbrowsaffected++;
1595
				}
1596
			}
1597
1598
			// If user is linked to a member, remove old link to this member
1599
			if ($this->fk_member > 0)
1600
			{
1601
				dol_syslog(get_class($this)."::update remove link with member. We will recreate it later", LOG_DEBUG);
1602
				$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = NULL where fk_member = ".$this->fk_member;
1603
				$resql = $this->db->query($sql);
1604
				if (! $resql) { $this->error=$this->db->error(); $this->db->rollback(); return -5; }
1605
			}
1606
			// Set link to user
1607
			dol_syslog(get_class($this)."::update set link with member", LOG_DEBUG);
1608
			$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member =".($this->fk_member>0?$this->fk_member:'null')." where rowid = ".$this->id;
1609
			$resql = $this->db->query($sql);
1610
			if (! $resql) { $this->error=$this->db->error(); $this->db->rollback(); return -5; }
1611
1612
			if ($nbrowsaffected)	// If something has changed in data
1613
			{
1614
				if ($this->fk_member > 0 && ! $nosyncmember)
1615
				{
1616
					dol_syslog(get_class($this)."::update user is linked with a member. We try to update member too.", LOG_DEBUG);
1617
1618
					require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
1619
1620
					// This user is linked with a member, so we also update member information
1621
					// if this is an update.
1622
					$adh=new Adherent($this->db);
1623
					$result=$adh->fetch($this->fk_member);
1624
1625
					if ($result > 0)
1626
					{
1627
						$adh->firstname=$this->firstname;
1628
						$adh->lastname=$this->lastname;
1629
						$adh->login=$this->login;
1630
						$adh->gender=$this->gender;
1631
						$adh->birth=$this->birth;
1632
1633
						$adh->pass=$this->pass;
1634
1635
						$adh->societe=(empty($adh->societe) && $this->societe_id ? $this->societe_id : $adh->societe);
1636
1637
						$adh->address=$this->address;
1638
						$adh->town=$this->town;
1639
						$adh->zip=$this->zip;
1640
						$adh->state_id=$this->state_id;
1641
						$adh->country_id=$this->country_id;
1642
1643
						$adh->email=$this->email;
1644
1645
						$adh->skype=$this->skype;
1646
						$adh->twitter=$this->twitter;
1647
						$adh->facebook=$this->facebook;
1648
						$adh->linkedin=$this->linkedin;
1649
1650
						$adh->phone=$this->office_phone;
1651
						$adh->phone_mobile=$this->user_mobile;
1652
1653
						$adh->user_id=$this->id;
1654
						$adh->user_login=$this->login;
1655
1656
						$result=$adh->update($user, 0, 1, 0);
1657
						if ($result < 0)
1658
						{
1659
							$this->error=$adh->error;
1660
							$this->errors=$adh->errors;
1661
							dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
1662
							$error++;
1663
						}
1664
					}
1665
					elseif ($result < 0)
1666
					{
1667
						$this->error=$adh->error;
1668
						$this->errors=$adh->errors;
1669
						$error++;
1670
					}
1671
				}
1672
1673
				if ($this->contact_id > 0 && ! $nosynccontact)
1674
				{
1675
					dol_syslog(get_class($this)."::update user is linked with a contact. We try to update contact too.", LOG_DEBUG);
1676
1677
					require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1678
1679
					// This user is linked with a contact, so we also update contact information
1680
					// if this is an update.
1681
					$tmpobj=new Contact($this->db);
1682
					$result=$tmpobj->fetch($this->contact_id);
1683
1684
					if ($result >= 0)
1685
					{
1686
						$tmpobj->firstname=$this->firstname;
1687
						$tmpobj->lastname=$this->lastname;
1688
						$tmpobj->login=$this->login;
1689
						$tmpobj->gender=$this->gender;
1690
						$tmpobj->birth=$this->birth;
1691
1692
						//$tmpobj->pass=$this->pass;
1693
1694
						//$tmpobj->societe=(empty($tmpobj->societe) && $this->societe_id ? $this->societe_id : $tmpobj->societe);
1695
1696
						$tmpobj->email=$this->email;
1697
1698
						$tmpobj->skype=$this->skype;
1699
						$tmpobj->twitter=$this->twitter;
1700
						$tmpobj->facebook=$this->facebook;
1701
						$tmpobj->linkedin=$this->linkedin;
1702
1703
						$tmpobj->phone_pro=$this->office_phone;
1704
						$tmpobj->phone_mobile=$this->user_mobile;
1705
						$tmpobj->fax=$this->office_fax;
1706
1707
						$tmpobj->address=$this->address;
1708
						$tmpobj->town=$this->town;
1709
						$tmpobj->zip=$this->zip;
1710
						$tmpobj->state_id=$this->state_id;
1711
						$tmpobj->country_id=$this->country_id;
1712
1713
						$tmpobj->user_id=$this->id;
1714
						$tmpobj->user_login=$this->login;
1715
1716
						$result=$tmpobj->update($tmpobj->id, $user, 0, 'update', 1);
1717
						if ($result < 0)
1718
						{
1719
							$this->error=$tmpobj->error;
1720
							$this->errors=$tmpobj->errors;
1721
							dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
1722
							$error++;
1723
						}
1724
					}
1725
					else
1726
					{
1727
						$this->error=$tmpobj->error;
1728
						$this->errors=$tmpobj->errors;
1729
						$error++;
1730
					}
1731
				}
1732
			}
1733
1734
			$action='update';
1735
1736
			// Actions on extra fields
1737
			if (! $error && empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))
1738
			{
1739
				$result=$this->insertExtraFields();
1740
				if ($result < 0)
1741
				{
1742
					$error++;
1743
				}
1744
			}
1745
1746
			if (! $error && ! $notrigger)
1747
			{
1748
				// Call trigger
1749
				$result=$this->call_trigger('USER_MODIFY', $user);
1750
				if ($result < 0) { $error++; }
1751
				// End call triggers
1752
			}
1753
1754
			if (! $error)
1755
			{
1756
				$this->db->commit();
1757
				return $nbrowsaffected;
1758
			}
1759
			else
1760
			{
1761
				dol_syslog(get_class($this)."::update error=".$this->error, LOG_ERR);
1762
				$this->db->rollback();
1763
				return -1;
1764
			}
1765
		}
1766
		else
1767
		{
1768
			$this->error=$this->db->lasterror();
1769
			$this->db->rollback();
1770
			return -2;
1771
		}
1772
	}
1773
1774
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1775
	/**
1776
	 *    Mise a jour en base de la date de derniere connexion d'un utilisateur
1777
	 *	  Fonction appelee lors d'une nouvelle connexion
1778
	 *
1779
	 *    @return     <0 si echec, >=0 si ok
0 ignored issues
show
Documentation Bug introduced by
The doc comment <0 at position 0 could not be parsed: Unknown type name '<' at position 0 in <0.
Loading history...
1780
	 */
1781
	public function update_last_login_date()
1782
	{
1783
        // phpcs:enable
1784
		$now=dol_now();
1785
1786
		$sql = "UPDATE ".MAIN_DB_PREFIX."user SET";
1787
		$sql.= " datepreviouslogin = datelastlogin,";
1788
		$sql.= " datelastlogin = '".$this->db->idate($now)."',";
1789
		$sql.= " tms = tms";    // La date de derniere modif doit changer sauf pour la mise a jour de date de derniere connexion
1790
		$sql.= " WHERE rowid = ".$this->id;
1791
1792
		dol_syslog(get_class($this)."::update_last_login_date user->id=".$this->id." ".$sql, LOG_DEBUG);
1793
		$resql = $this->db->query($sql);
1794
		if ($resql)
1795
		{
1796
			$this->datepreviouslogin=$this->datelastlogin;
1797
			$this->datelastlogin=$now;
1798
			return 1;
1799
		}
1800
		else
1801
		{
1802
			$this->error=$this->db->lasterror().' sql='.$sql;
1803
			return -1;
1804
		}
1805
	}
1806
1807
1808
	/**
1809
	 *  Change password of a user
1810
	 *
1811
	 *  @param	User	$user             		Object user of user making change
1812
	 *  @param  string	$password         		New password in clear text (to generate if not provided)
1813
	 *	@param	int		$changelater			1=Change password only after clicking on confirm email
1814
	 *	@param	int		$notrigger				1=Does not launch triggers
1815
	 *	@param	int		$nosyncmember	        Do not synchronize linked member
1816
	 *  @return string 			          		If OK return clear password, 0 if no change, < 0 if error
1817
	 */
1818
	public function setPassword($user, $password = '', $changelater = 0, $notrigger = 0, $nosyncmember = 0)
1819
	{
1820
		global $conf, $langs;
1821
		require_once DOL_DOCUMENT_ROOT .'/core/lib/security2.lib.php';
1822
1823
		$error=0;
1824
1825
		dol_syslog(get_class($this)."::setPassword user=".$user->id." password=".preg_replace('/./i', '*', $password)." changelater=".$changelater." notrigger=".$notrigger." nosyncmember=".$nosyncmember, LOG_DEBUG);
1826
1827
		// If new password not provided, we generate one
1828
		if (! $password)
1829
		{
1830
			$password=getRandomPassword(false);
1831
		}
1832
1833
		// Crypt password
1834
		$password_crypted = dol_hash($password);
1835
1836
		// Mise a jour
1837
		if (! $changelater)
1838
		{
1839
			if (! is_object($this->oldcopy)) $this->oldcopy = clone $this;
1840
1841
			$this->db->begin();
1842
1843
			$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1844
			$sql.= " SET pass_crypted = '".$this->db->escape($password_crypted)."',";
1845
			$sql.= " pass_temp = null";
1846
			if (! empty($conf->global->DATABASE_PWD_ENCRYPTED))
1847
			{
1848
				$sql.= ", pass = null";
1849
			}
1850
			else
1851
			{
1852
				$sql.= ", pass = '".$this->db->escape($password)."'";
1853
			}
1854
			$sql.= " WHERE rowid = ".$this->id;
1855
1856
			dol_syslog(get_class($this)."::setPassword", LOG_DEBUG);
1857
			$result = $this->db->query($sql);
1858
			if ($result)
1859
			{
1860
				if ($this->db->affected_rows($result))
1861
				{
1862
					$this->pass=$password;
1863
					$this->pass_indatabase=$password;
1864
					$this->pass_indatabase_crypted=$password_crypted;
1865
1866
					if ($this->fk_member && ! $nosyncmember)
1867
					{
1868
						require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
1869
1870
						// This user is linked with a member, so we also update members informations
1871
						// if this is an update.
1872
						$adh=new Adherent($this->db);
1873
						$result=$adh->fetch($this->fk_member);
1874
1875
						if ($result >= 0)
1876
						{
1877
							$result=$adh->setPassword($user, $this->pass, (empty($conf->global->DATABASE_PWD_ENCRYPTED)?0:1), 1);	// Cryptage non gere dans module adherent
1878
							if ($result < 0)
1879
							{
1880
								$this->error=$adh->error;
1881
								dol_syslog(get_class($this)."::setPassword ".$this->error, LOG_ERR);
1882
								$error++;
1883
							}
1884
						}
1885
						else
1886
						{
1887
							$this->error=$adh->error;
1888
							$error++;
1889
						}
1890
					}
1891
1892
					dol_syslog(get_class($this)."::setPassword notrigger=".$notrigger." error=".$error, LOG_DEBUG);
1893
1894
					if (! $error && ! $notrigger)
1895
					{
1896
						// Call trigger
1897
						$result=$this->call_trigger('USER_NEW_PASSWORD', $user);
1898
						if ($result < 0) { $error++; $this->db->rollback(); return -1; }
1899
						// End call triggers
1900
					}
1901
1902
					$this->db->commit();
1903
					return $this->pass;
1904
				}
1905
				else
1906
				{
1907
					$this->db->rollback();
1908
					return 0;
1909
				}
1910
			}
1911
			else
1912
			{
1913
				$this->db->rollback();
1914
				dol_print_error($this->db);
1915
				return -1;
1916
			}
1917
		}
1918
		else
1919
		{
1920
			// We store clear password in password temporary field.
1921
			// After receiving confirmation link, we will crypt it and store it in pass_crypted
1922
			$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1923
			$sql.= " SET pass_temp = '".$this->db->escape($password)."'";
1924
			$sql.= " WHERE rowid = ".$this->id;
1925
1926
			dol_syslog(get_class($this)."::setPassword", LOG_DEBUG);	// No log
1927
			$result = $this->db->query($sql);
1928
			if ($result)
1929
			{
1930
				return $password;
1931
			}
1932
			else
1933
			{
1934
				dol_print_error($this->db);
1935
				return -3;
1936
			}
1937
		}
1938
	}
1939
1940
1941
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1942
	/**
1943
	 *  Send new password by email
1944
	 *
1945
	 *  @param	User	$user           Object user that send email
1946
	 *  @param	string	$password       New password
1947
	 *	@param	int		$changelater	0=Send clear passwod into email, 1=Change password only after clicking on confirm email. @TODO Add method 2 = Send link to reset password
1948
	 *  @return int 		            < 0 si erreur, > 0 si ok
1949
	 */
1950
	public function send_password($user, $password = '', $changelater = 0)
1951
	{
1952
        // phpcs:enable
1953
		global $conf, $langs;
1954
		global $dolibarr_main_url_root;
1955
1956
		require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
1957
1958
		$msgishtml=0;
1959
1960
		// Define $msg
1961
		$mesg = '';
1962
1963
		$outputlangs=new Translate("", $conf);
1964
1965
		if (isset($this->conf->MAIN_LANG_DEFAULT)
1966
		&& $this->conf->MAIN_LANG_DEFAULT != 'auto')
1967
		{	// If user has defined its own language (rare because in most cases, auto is used)
1968
			$outputlangs->getDefaultLang($this->conf->MAIN_LANG_DEFAULT);
1969
		}
1970
		if($user->conf->MAIN_LANG_DEFAULT){
1971
            $outputlangs->setDefaultLang($user->conf->MAIN_LANG_DEFAULT);
1972
        }
1973
		else
1974
		{	// If user has not defined its own language, we used current language
1975
			$outputlangs=$langs;
1976
		}
1977
1978
        // Load translation files required by the page
1979
		$outputlangs->loadLangs(array("main", "errors", "users", "other"));
1980
1981
		$appli=constant('DOL_APPLICATION_TITLE');
1982
		if (!empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE;
1983
1984
		$subject = $outputlangs->transnoentitiesnoconv("SubjectNewPassword", $appli);
1985
1986
		// Define $urlwithroot
1987
		$urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
1988
		$urlwithroot=$urlwithouturlroot.DOL_URL_ROOT;		// This is to use external domain name found into config file
1989
1990
		if (! $changelater)
1991
		{
1992
			$url = $urlwithroot.'/';
1993
			$mesg.= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived").".\n";
1994
			$mesg.= $outputlangs->transnoentitiesnoconv("NewKeyIs")." :\n\n";
1995
			$mesg.= $outputlangs->transnoentitiesnoconv("Login")." = ".$this->login."\n";
1996
			$mesg.= $outputlangs->transnoentitiesnoconv("Password")." = ".$password."\n\n";
1997
			$mesg.= "\n";
1998
1999
			$mesg.= $outputlangs->transnoentitiesnoconv("ClickHereToGoTo", $appli).': '.$url."\n\n";
2000
			$mesg.= "--\n";
2001
			$mesg.= $user->getFullName($outputlangs);	// Username that make then sending
2002
2003
			dol_syslog(get_class($this)."::send_password changelater is off, url=".$url);
2004
		}
2005
		else
2006
		{
2007
			$url = $urlwithroot.'/user/passwordforgotten.php?action=validatenewpassword&username='.urlencode($this->login)."&passwordhash=".dol_hash($password);
2008
2009
			$mesg.= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived")."\n";
2010
			$mesg.= $outputlangs->transnoentitiesnoconv("NewKeyWillBe")." :\n\n";
2011
			$mesg.= $outputlangs->transnoentitiesnoconv("Login")." = ".$this->login."\n";
2012
			$mesg.= $outputlangs->transnoentitiesnoconv("Password")." = ".$password."\n\n";
2013
			$mesg.= "\n";
2014
			$mesg.= $outputlangs->transnoentitiesnoconv("YouMustClickToChange")." :\n";
2015
			$mesg.= $url."\n\n";
2016
			$mesg.= $outputlangs->transnoentitiesnoconv("ForgetIfNothing")."\n\n";
2017
2018
			dol_syslog(get_class($this)."::send_password changelater is on, url=".$url);
2019
		}
2020
2021
        $mailfile = new CMailFile(
2022
            $subject,
2023
			$this->email,
2024
			$conf->global->MAIN_MAIL_EMAIL_FROM,
2025
			$mesg,
2026
			array(),
2027
			array(),
2028
			array(),
2029
			'',
2030
			'',
2031
			0,
2032
            $msgishtml
2033
        );
2034
2035
		if ($mailfile->sendfile())
2036
		{
2037
			return 1;
2038
		}
2039
		else
2040
		{
2041
			$langs->trans("errors");
2042
			$this->error=$langs->trans("ErrorFailedToSendPassword").' '.$mailfile->error;
2043
			return -1;
2044
		}
2045
	}
2046
2047
	/**
2048
	 * 		Renvoie la derniere erreur fonctionnelle de manipulation de l'objet
2049
	 *
2050
	 * 		@return    string      chaine erreur
2051
	 */
2052
	public function error()
2053
	{
2054
		return $this->error;
2055
	}
2056
2057
2058
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2059
	/**
2060
	 *    	Read clicktodial information for user
2061
	 *
2062
	 * 		@return		<0 if KO, >0 if OK
0 ignored issues
show
Documentation Bug introduced by
The doc comment <0 at position 0 could not be parsed: Unknown type name '<' at position 0 in <0.
Loading history...
2063
	 */
2064
	public function fetch_clicktodial()
2065
	{
2066
        // phpcs:enable
2067
		$sql = "SELECT url, login, pass, poste ";
2068
		$sql.= " FROM ".MAIN_DB_PREFIX."user_clicktodial as u";
2069
		$sql.= " WHERE u.fk_user = ".$this->id;
2070
2071
		$resql = $this->db->query($sql);
2072
		if ($resql)
2073
		{
2074
			if ($this->db->num_rows($resql))
2075
			{
2076
				$obj = $this->db->fetch_object($resql);
2077
2078
				$this->clicktodial_url = $obj->url;
2079
				$this->clicktodial_login = $obj->login;
2080
				$this->clicktodial_password = $obj->pass;
2081
				$this->clicktodial_poste = $obj->poste;
2082
			}
2083
2084
			$this->clicktodial_loaded = 1;	// Data loaded (found or not)
2085
2086
			$this->db->free($resql);
2087
			return 1;
2088
		}
2089
		else
2090
		{
2091
			$this->error=$this->db->error();
2092
			return -1;
2093
		}
2094
	}
2095
2096
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2097
	/**
2098
	 *  Update clicktodial info
2099
	 *
2100
	 *  @return	integer
2101
     */
2102
    public function update_clicktodial()
2103
    {
2104
        // phpcs:enable
2105
		$this->db->begin();
2106
2107
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_clicktodial";
2108
		$sql .= " WHERE fk_user = ".$this->id;
2109
2110
		dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2111
		$result = $this->db->query($sql);
2112
2113
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."user_clicktodial";
2114
		$sql .= " (fk_user,url,login,pass,poste)";
2115
		$sql .= " VALUES (".$this->id;
2116
		$sql .= ", '". $this->db->escape($this->clicktodial_url) ."'";
2117
		$sql .= ", '". $this->db->escape($this->clicktodial_login) ."'";
2118
		$sql .= ", '". $this->db->escape($this->clicktodial_password) ."'";
2119
		$sql .= ", '". $this->db->escape($this->clicktodial_poste) ."')";
2120
2121
		dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2122
		$result = $this->db->query($sql);
2123
		if ($result)
2124
		{
2125
			$this->db->commit();
2126
			return 1;
2127
		}
2128
		else
2129
		{
2130
			$this->db->rollback();
2131
			$this->error=$this->db->lasterror();
2132
			return -1;
2133
		}
2134
    }
2135
2136
2137
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2138
	/**
2139
	 *  Add user into a group
2140
	 *
2141
	 *  @param	int	$group      Id of group
2142
	 *  @param  int		$entity     Entity
2143
	 *  @param  int		$notrigger  Disable triggers
2144
	 *  @return int  				<0 if KO, >0 if OK
2145
	 */
2146
	public function SetInGroup($group, $entity, $notrigger = 0)
2147
	{
2148
        // phpcs:enable
2149
		global $conf, $langs, $user;
2150
2151
		$error=0;
2152
2153
		$this->db->begin();
2154
2155
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."usergroup_user";
2156
		$sql.= " WHERE fk_user  = ".$this->id;
2157
		$sql.= " AND fk_usergroup = ".$group;
2158
		$sql.= " AND entity = ".$entity;
2159
2160
		$result = $this->db->query($sql);
2161
2162
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."usergroup_user (entity, fk_user, fk_usergroup)";
2163
		$sql.= " VALUES (".$entity.",".$this->id.",".$group.")";
2164
2165
		$result = $this->db->query($sql);
2166
		if ($result)
2167
		{
2168
			if (! $error && ! $notrigger)
2169
			{
2170
				$this->newgroupid=$group;    // deprecated. Remove this.
2171
				$this->context = array('audit'=>$langs->trans("UserSetInGroup"), 'newgroupid'=>$group);
2172
2173
				// Call trigger
2174
				$result=$this->call_trigger('USER_MODIFY', $user);
2175
				if ($result < 0) { $error++; }
2176
				// End call triggers
2177
			}
2178
2179
			if (! $error)
2180
			{
2181
				$this->db->commit();
2182
				return 1;
2183
			}
2184
			else
2185
			{
2186
				dol_syslog(get_class($this)."::SetInGroup ".$this->error, LOG_ERR);
2187
				$this->db->rollback();
2188
				return -2;
2189
			}
2190
		}
2191
		else
2192
		{
2193
			$this->error=$this->db->lasterror();
2194
			$this->db->rollback();
2195
			return -1;
2196
		}
2197
	}
2198
2199
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2200
	/**
2201
	 *  Remove a user from a group
2202
	 *
2203
	 *  @param	int   $group       Id of group
2204
	 *  @param  int		$entity      Entity
2205
	 *  @param  int		$notrigger   Disable triggers
2206
	 *  @return int  			     <0 if KO, >0 if OK
2207
	 */
2208
	public function RemoveFromGroup($group, $entity, $notrigger = 0)
2209
	{
2210
        // phpcs:enable
2211
		global $conf,$langs,$user;
2212
2213
		$error=0;
2214
2215
		$this->db->begin();
2216
2217
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."usergroup_user";
2218
		$sql.= " WHERE fk_user  = ".$this->id;
2219
		$sql.= " AND fk_usergroup = ".$group;
2220
		$sql.= " AND entity = ".$entity;
2221
2222
		$result = $this->db->query($sql);
2223
		if ($result)
2224
		{
2225
			if (! $error && ! $notrigger)
2226
			{
2227
				$this->oldgroupid=$group;    // deprecated. Remove this.
2228
				$this->context = array('audit'=>$langs->trans("UserRemovedFromGroup"), 'oldgroupid'=>$group);
2229
2230
				// Call trigger
2231
				$result=$this->call_trigger('USER_MODIFY', $user);
2232
				if ($result < 0) { $error++; }
2233
				// End call triggers
2234
			}
2235
2236
			if (! $error)
2237
			{
2238
				$this->db->commit();
2239
				return 1;
2240
			}
2241
			else
2242
			{
2243
				$this->error=$interface->error;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $interface seems to be never defined.
Loading history...
2244
				dol_syslog(get_class($this)."::RemoveFromGroup ".$this->error, LOG_ERR);
2245
				$this->db->rollback();
2246
				return -2;
2247
			}
2248
		}
2249
		else
2250
		{
2251
			$this->error=$this->db->lasterror();
2252
			$this->db->rollback();
2253
			return -1;
2254
		}
2255
	}
2256
2257
2258
	/**
2259
	 *  Return a link with photo
2260
	 * 	Use this->id,this->photo
2261
	 *
2262
	 *	@param	int		$width			Width of image
2263
	 *	@param	int		$height			Height of image
2264
	 *  @param	string	$cssclass		Force a css class
2265
	 * 	@param	string	$imagesize		'mini', 'small' or '' (original)
2266
	 *	@return	string					String with URL link
2267
	 */
2268
	public function getPhotoUrl($width, $height, $cssclass = '', $imagesize = '')
2269
	{
2270
		$result ='<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
2271
		$result.=Form::showphoto('userphoto', $this, $width, $height, 0, $cssclass, $imagesize);
2272
		$result.='</a>';
2273
2274
		return $result;
2275
	}
2276
2277
	/**
2278
	 *  Return a link to the user card (with optionaly the picto)
2279
	 * 	Use this->id,this->lastname, this->firstname
2280
	 *
2281
	 *	@param	int		$withpictoimg				Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto, -1=Include photo into link, -2=Only picto photo, -3=Only photo very small)
2282
	 *	@param	string	$option						On what the link point to ('leave', 'nolink', )
2283
	 *  @param  integer $infologin      			0=Add default info tooltip, 1=Add complete info tooltip, -1=No info tooltip
2284
	 *  @param	integer	$notooltip					1=Disable tooltip on picto and name
2285
	 *  @param	int		$maxlen						Max length of visible user name
2286
	 *  @param	int		$hidethirdpartylogo			Hide logo of thirdparty if user is external user
2287
	 *  @param  string  $mode               		''=Show firstname and lastname, 'firstname'=Show only firstname, 'firstelselast'=Show firstname or lastname if not defined, 'login'=Show login
2288
	 *  @param  string  $morecss            		Add more css on link
2289
	 *  @param  int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
2290
	 *	@return	string								String with URL
2291
	 */
2292
	public function getNomUrl($withpictoimg = 0, $option = '', $infologin = 0, $notooltip = 0, $maxlen = 24, $hidethirdpartylogo = 0, $mode = '', $morecss = '', $save_lastsearch_value = -1)
2293
	{
2294
		global $langs, $conf, $db, $hookmanager, $user;
2295
		global $dolibarr_main_authentication, $dolibarr_main_demo;
2296
		global $menumanager;
2297
2298
        if(!$user->rights->user->user->lire && $user->id !=$this->id) $option='nolink';
2299
2300
		if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpictoimg) $withpictoimg=0;
2301
2302
		$result=''; $label='';
2303
2304
		if (! empty($this->photo))
2305
		{
2306
			$label.= '<div class="photointooltip">';
2307
			$label.= Form::showphoto('userphoto', $this, 0, 60, 0, 'photowithmargin photologintooltip', 'small', 0, 1);	// Force height to 60 so we total height of tooltip can be calculated and collision can be managed
2308
			$label.= '</div><div style="clear: both;"></div>';
2309
		}
2310
2311
		// Info Login
2312
		$label.= '<div class="centpercent">';
2313
		$label.= '<u>' . $langs->trans("User") . '</u><br>';
2314
		$label.= '<b>' . $langs->trans('Name') . ':</b> ' . $this->getFullName($langs, '');
2315
		if (! empty($this->login))
2316
			$label.= '<br><b>' . $langs->trans('Login') . ':</b> ' . $this->login;
2317
		$label.= '<br><b>' . $langs->trans("EMail").':</b> '.$this->email;
2318
		if (! empty($this->admin))
2319
			$label.= '<br><b>' . $langs->trans("Administrator").'</b>: '.yn($this->admin);
2320
		if (! empty($this->socid) )	// Add thirdparty for external users
2321
		{
2322
			$thirdpartystatic = new Societe($db);
2323
			$thirdpartystatic->fetch($this->socid);
2324
			if (empty($hidethirdpartylogo)) $companylink = ' '.$thirdpartystatic->getNomUrl(2, (($option == 'nolink')?'nolink':''));	// picto only of company
2325
			$company=' ('.$langs->trans("Company").': '.$thirdpartystatic->name.')';
2326
		}
2327
		$type=($this->socid?$langs->trans("External").$company:$langs->trans("Internal"));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $company does not seem to be defined for all execution paths leading up to this point.
Loading history...
2328
		$label.= '<br><b>' . $langs->trans("Type") . ':</b> ' . $type;
2329
		$label.= '<br><b>' . $langs->trans("Status").'</b>: '.$this->getLibStatut(0);
2330
		$label.='</div>';
2331
		if ($infologin > 0)
2332
		{
2333
			$label.= '<br>';
2334
			$label.= '<br><u>'.$langs->trans("Session").'</u>';
2335
			$label.= '<br><b>'.$langs->trans("IPAddress").'</b>: '.$_SERVER["REMOTE_ADDR"];
2336
			if (! empty($conf->global->MAIN_MODULE_MULTICOMPANY)) $label.= '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (user entity '.$this->entity.')';
2337
			$label.= '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.$_SESSION["dol_authmode"].(empty($dolibarr_main_demo)?'':' (demo)');
2338
			$label.= '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($this->datelastlogin, "dayhour", 'tzuser');
2339
			$label.= '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($this->datepreviouslogin, "dayhour", 'tzuser');
2340
			$label.= '<br><b>'.$langs->trans("CurrentTheme").':</b> '.$conf->theme;
2341
			$label.= '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.$menumanager->name;
2342
			$s=picto_from_langcode($langs->getDefaultLang());
2343
			$label.= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.($s?$s.' ':'').$langs->getDefaultLang();
2344
			$label.= '<br><b>'.$langs->trans("Browser").':</b> '.$conf->browser->name.($conf->browser->version?' '.$conf->browser->version:'').' ('.$_SERVER['HTTP_USER_AGENT'].')';
2345
			$label.= '<br><b>'.$langs->trans("Layout").':</b> '.$conf->browser->layout;
2346
			$label.= '<br><b>'.$langs->trans("Screen").':</b> '.$_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight'];
2347
			if ($conf->browser->layout == 'phone') $label.= '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
2348
			if (! empty($_SESSION["disablemodules"])) $label.= '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.join(', ', explode(',', $_SESSION["disablemodules"]));
2349
		}
2350
		if ($infologin < 0) $label='';
2351
2352
		$url = DOL_URL_ROOT.'/user/card.php?id='.$this->id;
2353
		if ($option == 'leave') $url = DOL_URL_ROOT.'/holiday/list.php?id='.$this->id;
2354
2355
		if ($option != 'nolink')
2356
		{
2357
			// Add param to save lastsearch_values or not
2358
			$add_save_lastsearch_values=($save_lastsearch_value == 1 ? 1 : 0);
2359
			if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values=1;
2360
			if ($add_save_lastsearch_values) $url.='&save_lastsearch_values=1';
2361
		}
2362
2363
		$linkstart='<a href="'.$url.'"';
2364
		$linkclose="";
2365
		if (empty($notooltip))
2366
		{
2367
			if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER))
2368
			{
2369
				$langs->load("users");
2370
				$label=$langs->trans("ShowUser");
2371
				$linkclose.=' alt="'.dol_escape_htmltag($label, 1).'"';
2372
			}
2373
			$linkclose.= ' title="'.dol_escape_htmltag($label, 1).'"';
2374
			$linkclose.= ' class="classfortooltip'.($morecss?' '.$morecss:'').'"';
2375
2376
			/*
2377
			 $hookmanager->initHooks(array('userdao'));
2378
			 $parameters=array('id'=>$this->id);
2379
			 $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
2380
			 if ($reshook > 0) $linkclose = $hookmanager->resPrint;
2381
			 */
2382
		}
2383
2384
		$linkstart.=$linkclose.'>';
2385
		$linkend='</a>';
2386
2387
		//if ($withpictoimg == -1) $result.='<div class="nowrap">';
2388
		$result.=(($option == 'nolink')?'':$linkstart);
2389
		if ($withpictoimg)
2390
		{
2391
		  	$paddafterimage='';
2392
		  	if (abs($withpictoimg) == 1) $paddafterimage='style="margin-'.($langs->trans("DIRECTION")=='rtl'?'left':'right').': 3px;"';
2393
			// Only picto
2394
			if ($withpictoimg > 0) $picto='<!-- picto user --><div class="inline-block nopadding userimg'.($morecss?' '.$morecss:'').'">'.img_object('', 'user', $paddafterimage.' '.($notooltip?'':'class="classfortooltip"'), 0, 0, $notooltip?0:1).'</div>';
2395
			// Picto must be a photo
2396
			else $picto='<!-- picto photo user --><div class="inline-block nopadding userimg'.($morecss?' '.$morecss:'').'"'.($paddafterimage?' '.$paddafterimage:'').'>'.Form::showphoto('userphoto', $this, 0, 0, 0, 'userphoto'.($withpictoimg==-3?'small':''), 'mini', 0, 1).'</div>';
2397
			$result.=$picto;
2398
		}
2399
		if ($withpictoimg > -2 && $withpictoimg != 2)
2400
		{
2401
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $result.='<div class="inline-block nopadding valignmiddle usertext'.((! isset($this->statut) || $this->statut)?'':' strikefordisabled').($morecss?' '.$morecss:'').'">';
2402
			if ($mode == 'login') $result.=dol_trunc($this->login, $maxlen);
2403
			else $result.=$this->getFullName($langs, '', ($mode == 'firstelselast' ? 3 : ($mode == 'firstname' ? 2 : -1)), $maxlen);
2404
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) $result.='</div>';
2405
		}
2406
		$result.=(($option == 'nolink')?'':$linkend);
2407
		//if ($withpictoimg == -1) $result.='</div>';
2408
2409
		$result.=$companylink;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $companylink does not seem to be defined for all execution paths leading up to this point.
Loading history...
2410
2411
		global $action;
2412
		$hookmanager->initHooks(array('userdao'));
2413
		$parameters=array('id'=>$this->id, 'getnomurl'=>$result);
2414
		$reshook=$hookmanager->executeHooks('getNomUrl', $parameters, $this, $action);    // Note that $action and $object may have been modified by some hooks
2415
		if ($reshook > 0) $result = $hookmanager->resPrint;
2416
		else $result .= $hookmanager->resPrint;
2417
2418
		return $result;
2419
	}
2420
2421
	/**
2422
	 *  Return clickable link of login (eventualy with picto)
2423
	 *
2424
	 *	@param	int		$withpicto		Include picto into link
2425
	 *	@param	string	$option			Sur quoi pointe le lien
2426
	 *	@return	string					Chaine avec URL
2427
	 */
2428
	public function getLoginUrl($withpicto = 0, $option = '')
2429
	{
2430
		global $langs, $user;
2431
2432
		$result='';
2433
2434
		$linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
2435
		$linkend='</a>';
2436
2437
                //Check user's rights to see an other user
2438
                if((!$user->rights->user->user->lire && $this->id !=$user->id)) $option='nolink';
2439
2440
		if ($option == 'xxx')
2441
		{
2442
			$linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
2443
			$linkend='</a>';
2444
		}
2445
2446
        if ($option == 'nolink')
2447
		{
2448
			$linkstart = '';
2449
			$linkend='';
2450
		}
2451
2452
		$result.=$linkstart;
2453
		if ($withpicto) $result.=img_object($langs->trans("ShowUser"), 'user', 'class="paddingright"');
2454
		$result.=$this->login;
2455
		$result.=$linkend;
2456
		return $result;
2457
	}
2458
2459
	/**
2460
	 *  Return label of status of user (active, inactive)
2461
	 *
2462
	 *  @param	int		$mode          0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
2463
	 *  @return	string 			       Label of status
2464
	 */
2465
	public function getLibStatut($mode = 0)
2466
	{
2467
		return $this->LibStatut($this->statut, $mode);
2468
	}
2469
2470
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2471
    /**
2472
     *  Renvoi le libelle d'un statut donne
2473
     *
2474
     *  @param  int     $statut         Id statut
2475
     *  @param  int     $mode           0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
2476
     *  @return string                  Label of status
2477
     */
2478
    public function LibStatut($statut, $mode = 0)
2479
    {
2480
        // phpcs:enable
2481
		global $langs;
2482
		$langs->load('users');
2483
2484
		if ($mode == 0)
2485
		{
2486
			if ($statut == 1) return $langs->trans('Enabled');
2487
			elseif ($statut == 0) return $langs->trans('Disabled');
2488
		}
2489
		elseif ($mode == 1)
2490
		{
2491
			if ($statut == 1) return $langs->trans('Enabled');
2492
			elseif ($statut == 0) return $langs->trans('Disabled');
2493
		}
2494
		elseif ($mode == 2)
2495
		{
2496
			if ($statut == 1) return img_picto($langs->trans('Enabled'), 'statut4', 'class="pictostatus"').' '.$langs->trans('Enabled');
2497
			elseif ($statut == 0) return img_picto($langs->trans('Disabled'), 'statut5', 'class="pictostatus"').' '.$langs->trans('Disabled');
2498
		}
2499
		elseif ($mode == 3)
2500
		{
2501
			if ($statut == 1) return img_picto($langs->trans('Enabled'), 'statut4', 'class="pictostatus"');
2502
			elseif ($statut == 0) return img_picto($langs->trans('Disabled'), 'statut5', 'class="pictostatus"');
2503
		}
2504
		elseif ($mode == 4)
2505
		{
2506
			if ($statut == 1) return img_picto($langs->trans('Enabled'), 'statut4', 'class="pictostatus"').' '.$langs->trans('Enabled');
2507
			elseif ($statut == 0) return img_picto($langs->trans('Disabled'), 'statut5', 'class="pictostatus"').' '.$langs->trans('Disabled');
2508
		}
2509
		elseif ($mode == 5)
2510
		{
2511
			if ($statut == 1) return $langs->trans('Enabled').' '.img_picto($langs->trans('Enabled'), 'statut4', 'class="pictostatus"');
2512
			elseif ($statut == 0) return $langs->trans('Disabled').' '.img_picto($langs->trans('Disabled'), 'statut5', 'class="pictostatus"');
2513
		}
2514
	}
2515
2516
2517
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2518
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2519
	/**
2520
	 *	Retourne chaine DN complete dans l'annuaire LDAP pour l'objet
2521
	 *
2522
	 *	@param	array	$info		Info array loaded by _load_ldap_info
2523
	 *	@param	int		$mode		0=Return full DN (uid=qqq,ou=xxx,dc=aaa,dc=bbb)
2524
	 *								1=Return parent (ou=xxx,dc=aaa,dc=bbb)
2525
	 *								2=Return key only (RDN) (uid=qqq)
2526
	 *	@return	string				DN
2527
	 */
2528
	public function _load_ldap_dn($info, $mode = 0)
2529
	{
2530
        // phpcs:enable
2531
		global $conf;
2532
		$dn='';
2533
		if ($mode==0) $dn=$conf->global->LDAP_KEY_USERS."=".$info[$conf->global->LDAP_KEY_USERS].",".$conf->global->LDAP_USER_DN;
2534
		elseif ($mode==1) $dn=$conf->global->LDAP_USER_DN;
2535
		elseif ($mode==2) $dn=$conf->global->LDAP_KEY_USERS."=".$info[$conf->global->LDAP_KEY_USERS];
2536
		return $dn;
2537
	}
2538
2539
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2540
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2541
	/**
2542
	 *	Initialize the info array (array of LDAP values) that will be used to call LDAP functions
2543
	 *
2544
	 *	@return		array		Tableau info des attributs
2545
	 */
2546
	public function _load_ldap_info()
2547
	{
2548
        // phpcs:enable
2549
		global $conf,$langs;
2550
2551
		$info=array();
2552
		$keymodified=false;
2553
2554
		// Object classes
2555
		$info["objectclass"]=explode(',', $conf->global->LDAP_USER_OBJECT_CLASS);
2556
2557
		$this->fullname=$this->getFullName($langs);
2558
2559
		// Possible LDAP KEY (constname => varname)
2560
		$ldapkey = array(
2561
			'LDAP_FIELD_FULLNAME'	=> 'fullname',
2562
			'LDAP_FIELD_NAME'		=> 'lastname',
2563
			'LDAP_FIELD_FIRSTNAME'	=> 'firstname',
2564
			'LDAP_FIELD_LOGIN'		=> 'login',
2565
			'LDAP_FIELD_LOGIN_SAMBA'=> 'login',
2566
			'LDAP_FIELD_PHONE'		=> 'office_phone',
2567
			'LDAP_FIELD_MOBILE'		=> 'user_mobile',
2568
			'LDAP_FIELD_FAX'		=> 'office_fax',
2569
			'LDAP_FIELD_MAIL'		=> 'email',
2570
			'LDAP_FIELD_SID'		=> 'ldap_sid',
2571
			'LDAP_FIELD_SKYPE'		=> 'skype',
2572
			'LDAP_FIELD_TWITTER'	=> 'twitter',
2573
			'LDAP_FIELD_FACEBOOK'	=> 'facebook',
2574
            'LDAP_FIELD_LINKEDIN'	=> 'linkedin'
2575
		);
2576
2577
		// Champs
2578
		foreach ($ldapkey as $constname => $varname)
2579
		{
2580
			if (! empty($this->$varname) && ! empty($conf->global->$constname))
2581
			{
2582
				$info[$conf->global->$constname] = $this->$varname;
2583
2584
				// Check if it is the LDAP key and if its value has been changed
2585
				if (! empty($conf->global->LDAP_KEY_USERS) && $conf->global->LDAP_KEY_USERS == $conf->global->$constname)
2586
				{
2587
					if (! empty($this->oldcopy) && $this->$varname != $this->oldcopy->$varname) $keymodified=true; // For check if LDAP key has been modified
2588
				}
2589
			}
2590
		}
2591
		if ($this->address && ! empty($conf->global->LDAP_FIELD_ADDRESS))			$info[$conf->global->LDAP_FIELD_ADDRESS] = $this->address;
2592
		if ($this->zip && ! empty($conf->global->LDAP_FIELD_ZIP))					$info[$conf->global->LDAP_FIELD_ZIP] = $this->zip;
2593
		if ($this->town && ! empty($conf->global->LDAP_FIELD_TOWN))					$info[$conf->global->LDAP_FIELD_TOWN] = $this->town;
2594
		if ($this->note_public && ! empty($conf->global->LDAP_FIELD_DESCRIPTION))	$info[$conf->global->LDAP_FIELD_DESCRIPTION] = dol_string_nohtmltag($this->note_public, 2);
2595
		if ($this->socid > 0)
2596
		{
2597
			$soc = new Societe($this->db);
2598
			$soc->fetch($this->socid);
2599
2600
			$info[$conf->global->LDAP_FIELD_COMPANY] = $soc->name;
2601
			if ($soc->client == 1)      $info["businessCategory"] = "Customers";
2602
			if ($soc->client == 2)      $info["businessCategory"] = "Prospects";
2603
			if ($soc->fournisseur == 1) $info["businessCategory"] = "Suppliers";
2604
		}
2605
2606
		// When password is modified
2607
		if (! empty($this->pass))
2608
		{
2609
			if (! empty($conf->global->LDAP_FIELD_PASSWORD))				$info[$conf->global->LDAP_FIELD_PASSWORD] = $this->pass;	// this->pass = mot de passe non crypte
2610
			if (! empty($conf->global->LDAP_FIELD_PASSWORD_CRYPTED))		$info[$conf->global->LDAP_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass, 4); // Create OpenLDAP MD5 password (TODO add type of encryption)
2611
		}
2612
		// Set LDAP password if possible
2613
		elseif ($conf->global->LDAP_SERVER_PROTOCOLVERSION !== '3') // If ldap key is modified and LDAPv3 we use ldap_rename function for avoid lose encrypt password
2614
		{
2615
			if (! empty($conf->global->DATABASE_PWD_ENCRYPTED))
2616
			{
2617
				// Just for the default MD5 !
2618
				if (empty($conf->global->MAIN_SECURITY_HASH_ALGO))
2619
				{
2620
					if ($this->pass_indatabase_crypted && ! empty($conf->global->LDAP_FIELD_PASSWORD_CRYPTED))	{
2621
						$info[$conf->global->LDAP_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass_indatabase_crypted, 5); // Create OpenLDAP MD5 password from Dolibarr MD5 password
2622
					}
2623
				}
2624
			}
2625
			// Use $this->pass_indatabase value if exists
2626
			elseif (! empty($this->pass_indatabase))
2627
			{
2628
				if (! empty($conf->global->LDAP_FIELD_PASSWORD))				$info[$conf->global->LDAP_FIELD_PASSWORD] = $this->pass_indatabase;	// $this->pass_indatabase = mot de passe non crypte
2629
				if (! empty($conf->global->LDAP_FIELD_PASSWORD_CRYPTED))		$info[$conf->global->LDAP_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass_indatabase, 4); // md5 for OpenLdap TODO add type of encryption
2630
			}
2631
		}
2632
2633
		if ($conf->global->LDAP_SERVER_TYPE == 'egroupware')
2634
		{
2635
			$info["objectclass"][4] = "phpgwContact"; // compatibilite egroupware
2636
2637
			$info['uidnumber'] = $this->id;
2638
2639
			$info['phpgwTz']      = 0;
2640
			$info['phpgwMailType'] = 'INTERNET';
2641
			$info['phpgwMailHomeType'] = 'INTERNET';
2642
2643
			$info["phpgwContactTypeId"] = 'n';
2644
			$info["phpgwContactCatId"] = 0;
2645
			$info["phpgwContactAccess"] = "public";
2646
2647
			if (dol_strlen($this->egroupware_id) == 0)
2648
			{
2649
				$this->egroupware_id = 1;
2650
			}
2651
2652
			$info["phpgwContactOwner"] = $this->egroupware_id;
2653
2654
			if ($this->email) $info["rfc822Mailbox"] = $this->email;
2655
			if ($this->phone_mobile) $info["phpgwCellTelephoneNumber"] = $this->phone_mobile;
2656
		}
2657
2658
		return $info;
2659
	}
2660
2661
2662
	/**
2663
	 *  Initialise an instance with random values.
2664
	 *  Used to build previews or test instances.
2665
	 *	id must be 0 if object instance is a specimen.
2666
	 *
2667
	 *  @return	void
2668
	 */
2669
	public function initAsSpecimen()
2670
	{
2671
		global $user,$langs;
2672
2673
		$now=dol_now();
2674
2675
		// Initialise parametres
2676
		$this->id=0;
2677
		$this->ref = 'SPECIMEN';
2678
		$this->specimen=1;
2679
2680
		$this->lastname='DOLIBARR';
2681
		$this->firstname='SPECIMEN';
2682
		$this->gender='man';
2683
		$this->note='This is a note';
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$note has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

2683
		/** @scrutinizer ignore-deprecated */ $this->note='This is a note';
Loading history...
2684
		$this->email='[email protected]';
2685
        $this->personal_email='[email protected]';
2686
		$this->skype='skypepseudo';
2687
		$this->twitter='twitterpseudo';
2688
		$this->facebook='facebookpseudo';
2689
		$this->linkedin='linkedinpseudo';
2690
		$this->office_phone='0999999999';
2691
		$this->office_fax='0999999998';
2692
		$this->user_mobile='0999999997';
2693
        $this->personal_mobile='0999999996';
2694
		$this->admin=0;
2695
		$this->login='dolibspec';
2696
		$this->pass='dolibspec';
2697
		//$this->pass_indatabase='dolibspec';									Set after a fetch
2698
		//$this->pass_indatabase_crypted='e80ca5a88c892b0aaaf7e154853bccab';	Set after a fetch
2699
		$this->datec=$now;
2700
		$this->datem=$now;
2701
2702
		$this->datelastlogin=$now;
2703
		$this->datepreviouslogin=$now;
2704
		$this->statut=1;
2705
2706
		//$this->societe_id = 1;	For external users
2707
		//$this->contact_id = 1;	For external users
2708
		$this->entity = 1;
2709
	}
2710
2711
	/**
2712
	 *  Load info of user object
2713
	 *
2714
	 *  @param  int		$id     Id of user to load
2715
	 *  @return	void
2716
	 */
2717
	public function info($id)
2718
	{
2719
		$sql = "SELECT u.rowid, u.login as ref, u.datec,";
2720
		$sql.= " u.tms as date_modification, u.entity";
2721
		$sql.= " FROM ".MAIN_DB_PREFIX."user as u";
2722
		$sql.= " WHERE u.rowid = ".$id;
2723
2724
		$result=$this->db->query($sql);
2725
		if ($result)
2726
		{
2727
			if ($this->db->num_rows($result))
2728
			{
2729
				$obj = $this->db->fetch_object($result);
2730
2731
				$this->id = $obj->rowid;
2732
2733
				$this->ref = (! $obj->ref) ? $obj->rowid : $obj->ref;
2734
				$this->date_creation = $this->db->jdate($obj->datec);
2735
				$this->date_modification = $this->db->jdate($obj->date_modification);
2736
				$this->entity = $obj->entity;
2737
			}
2738
2739
			$this->db->free($result);
2740
		}
2741
		else
2742
		{
2743
			dol_print_error($this->db);
2744
		}
2745
	}
2746
2747
2748
	/**
2749
	 *    Return number of mass Emailing received by this contacts with its email
2750
	 *
2751
	 *    @return       int     Number of EMailings
2752
	 */
2753
	public function getNbOfEMailings()
2754
	{
2755
		$sql = "SELECT count(mc.email) as nb";
2756
		$sql.= " FROM ".MAIN_DB_PREFIX."mailing_cibles as mc";
2757
		$sql.= " WHERE mc.email = '".$this->db->escape($this->email)."'";
2758
		$sql.= " AND mc.statut NOT IN (-1,0)";      // -1 erreur, 0 non envoye, 1 envoye avec succes
2759
2760
		$resql=$this->db->query($sql);
2761
		if ($resql)
2762
		{
2763
			$obj = $this->db->fetch_object($resql);
2764
			$nb=$obj->nb;
2765
2766
			$this->db->free($resql);
2767
			return $nb;
2768
		}
2769
		else
2770
		{
2771
			$this->error=$this->db->error();
2772
			return -1;
2773
		}
2774
	}
2775
2776
	/**
2777
	 *  Return number of existing users
2778
	 *
2779
	 *  @param	string	$limitTo	Limit to '' or 'active'
2780
	 *  @param	string	$option		'superadmin' = return for entity 0 only
2781
	 *  @param	int		$admin		Filter on admin tag
2782
	 *  @return int  				Number of users
2783
	 */
2784
	public function getNbOfUsers($limitTo, $option = '', $admin = -1)
2785
	{
2786
		global $conf;
2787
2788
		$sql = "SELECT count(rowid) as nb";
2789
		$sql.= " FROM ".MAIN_DB_PREFIX."user";
2790
		if ($option == 'superadmin')
2791
		{
2792
			$sql.= " WHERE entity = 0";
2793
			if ($admin >= 0) $sql.= " AND admin = ".$admin;
2794
		}
2795
		else
2796
		{
2797
			$sql.=" WHERE entity IN (".getEntity('user', 0).")";
2798
			if ($limitTo == 'active') $sql.= " AND statut = 1";
2799
			if ($admin >= 0) $sql.= " AND admin = ".$admin;
2800
		}
2801
2802
		$resql=$this->db->query($sql);
2803
		if ($resql)
2804
		{
2805
			$obj = $this->db->fetch_object($resql);
2806
			$nb=$obj->nb;
2807
2808
			$this->db->free($resql);
2809
			return $nb;
2810
		}
2811
		else
2812
		{
2813
			$this->error=$this->db->lasterror();
2814
			return -1;
2815
		}
2816
	}
2817
2818
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2819
	/**
2820
	 *  Update user using data from the LDAP
2821
	 *
2822
	 *  @param	Object	$ldapuser	Ladp User
2823
	 *  @return int  				<0 if KO, >0 if OK
2824
	 */
2825
	public function update_ldap2dolibarr(&$ldapuser)
2826
	{
2827
        // phpcs:enable
2828
		// TODO: Voir pourquoi le update met à jour avec toutes les valeurs vide (global $user écrase ?)
2829
		global $user, $conf;
2830
2831
		$this->firstname=$ldapuser->{$conf->global->LDAP_FIELD_FIRSTNAME};
2832
		$this->lastname=$ldapuser->{$conf->global->LDAP_FIELD_NAME};
2833
		$this->login=$ldapuser->{$conf->global->LDAP_FIELD_LOGIN};
2834
		$this->pass=$ldapuser->{$conf->global->LDAP_FIELD_PASSWORD};
2835
		$this->pass_indatabase_crypted=$ldapuser->{$conf->global->LDAP_FIELD_PASSWORD_CRYPTED};
2836
2837
		$this->office_phone=$ldapuser->{$conf->global->LDAP_FIELD_PHONE};
2838
		$this->user_mobile=$ldapuser->{$conf->global->LDAP_FIELD_MOBILE};
2839
		$this->office_fax=$ldapuser->{$conf->global->LDAP_FIELD_FAX};
2840
		$this->email=$ldapuser->{$conf->global->LDAP_FIELD_MAIL};
2841
		$this->skype=$ldapuser->{$conf->global->LDAP_FIELD_SKYPE};
2842
		$this->twitter=$ldapuser->{$conf->global->LDAP_FIELD_TWITTER};
2843
		$this->facebook=$ldapuser->{$conf->global->LDAP_FIELD_FACEBOOK};
2844
		$this->linkedin=$ldapuser->{$conf->global->LDAP_FIELD_LINKEDIN};
2845
		$this->ldap_sid=$ldapuser->{$conf->global->LDAP_FIELD_SID};
2846
2847
		$this->job=$ldapuser->{$conf->global->LDAP_FIELD_TITLE};
2848
		$this->note=$ldapuser->{$conf->global->LDAP_FIELD_DESCRIPTION};
1 ignored issue
show
Deprecated Code introduced by
The property CommonObject::$note has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

2848
		/** @scrutinizer ignore-deprecated */ $this->note=$ldapuser->{$conf->global->LDAP_FIELD_DESCRIPTION};
Loading history...
2849
2850
		$result = $this->update($user);
2851
2852
		dol_syslog(get_class($this)."::update_ldap2dolibarr result=".$result, LOG_DEBUG);
2853
2854
		return $result;
2855
	}
2856
2857
2858
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2859
	/**
2860
	 * Return and array with all instanciated first level children users of current user
2861
	 *
2862
	 * @return	void
2863
	 * @see getAllChildIds()
2864
	 */
2865
	public function get_children()
2866
	{
2867
        // phpcs:enable
2868
		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."user";
2869
		$sql.= " WHERE fk_user = ".$this->id;
2870
2871
		dol_syslog(get_class($this)."::get_children result=".$result, LOG_DEBUG);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result seems to be never defined.
Loading history...
2872
		$res  = $this->db->query($sql);
2873
		if ($res)
2874
		{
2875
			$users = array ();
2876
			while ($rec = $this->db->fetch_array($res))
2877
			{
2878
				$user = new User($this->db);
2879
				$user->fetch($rec['rowid']);
2880
				$users[] = $user;
2881
			}
2882
			return $users;
2883
		}
2884
		else
2885
		{
2886
			dol_print_error($this->db);
2887
			return -1;
2888
		}
2889
	}
2890
2891
2892
	/**
2893
	 *  Load this->parentof that is array(id_son=>id_parent, ...)
2894
	 *
2895
	 *  @return     int     <0 if KO, >0 if OK
2896
	 */
2897
	private function loadParentOf()
2898
	{
2899
		global $conf;
2900
2901
		$this->parentof=array();
2902
2903
		// Load array[child]=parent
2904
		$sql = "SELECT fk_user as id_parent, rowid as id_son";
2905
		$sql.= " FROM ".MAIN_DB_PREFIX."user";
2906
		$sql.= " WHERE fk_user <> 0";
2907
		$sql.= " AND entity IN (".getEntity('user').")";
2908
2909
		dol_syslog(get_class($this)."::loadParentOf", LOG_DEBUG);
2910
		$resql = $this->db->query($sql);
2911
		if ($resql)
2912
		{
2913
			while ($obj= $this->db->fetch_object($resql))
2914
			{
2915
				$this->parentof[$obj->id_son]=$obj->id_parent;
2916
			}
2917
			return 1;
2918
		}
2919
		else
2920
		{
2921
			dol_print_error($this->db);
2922
			return -1;
2923
		}
2924
	}
2925
2926
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2927
	/**
2928
	 * 	Reconstruit l'arborescence hierarchique des users sous la forme d'un tableau
2929
	 *	Set and return this->users that is an array sorted according to tree with arrays of:
2930
	 *				id = id user
2931
	 *				lastname
2932
	 *				firstname
2933
	 *				fullname = nom avec chemin complet du user
2934
	 *				fullpath = chemin complet compose des id: "_grandparentid_parentid_id"
2935
	 *
2936
	 *  @param      int		$deleteafterid      Removed all users including the leaf $deleteafterid (and all its child) in user tree.
2937
	 *  @param		string	$filter				SQL filter on users
2938
	 *	@return		array		      		  	Array of users $this->users. Note: $this->parentof is also set.
2939
	 */
2940
    public function get_full_tree($deleteafterid = 0, $filter = '')
2941
    {
2942
        // phpcs:enable
2943
		global $conf, $user;
2944
		global $hookmanager;
2945
2946
		// Actions hooked (by external module)
2947
		$hookmanager->initHooks(array('userdao'));
2948
2949
		$this->users = array();
2950
2951
		// Init this->parentof that is array(id_son=>id_parent, ...)
2952
		$this->loadParentOf();
2953
2954
		// Init $this->users array
2955
		$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
2956
		$sql.= " FROM ".MAIN_DB_PREFIX."user as u";
2957
		// Add fields from hooks
2958
		$parameters=array();
2959
		$reshook=$hookmanager->executeHooks('printUserListWhere', $parameters);    // Note that $action and $object may have been modified by hook
2960
		if ($reshook > 0) {
2961
			$sql.=$hookmanager->resPrint;
2962
		} else {
2963
			$sql.= " WHERE u.entity IN (".getEntity('user').")";
2964
		}
2965
		if ($filter) $sql.=" AND ".$filter;
2966
2967
		dol_syslog(get_class($this)."::get_full_tree get user list", LOG_DEBUG);
2968
		$resql = $this->db->query($sql);
2969
		if ($resql)
2970
		{
2971
			$i=0;
2972
			while ($obj = $this->db->fetch_object($resql))
2973
			{
2974
				$this->users[$obj->rowid]['rowid'] = $obj->rowid;
2975
				$this->users[$obj->rowid]['id'] = $obj->rowid;
2976
				$this->users[$obj->rowid]['fk_user'] = $obj->fk_user;
2977
				$this->users[$obj->rowid]['fk_soc'] = $obj->fk_soc;
2978
				$this->users[$obj->rowid]['firstname'] = $obj->firstname;
2979
				$this->users[$obj->rowid]['lastname'] = $obj->lastname;
2980
				$this->users[$obj->rowid]['login'] = $obj->login;
2981
				$this->users[$obj->rowid]['statut'] = $obj->statut;
2982
				$this->users[$obj->rowid]['entity'] = $obj->entity;
2983
				$this->users[$obj->rowid]['email'] = $obj->email;
2984
				$this->users[$obj->rowid]['gender'] = $obj->gender;
2985
				$this->users[$obj->rowid]['admin'] = $obj->admin;
2986
				$this->users[$obj->rowid]['photo'] = $obj->photo;
2987
				$i++;
2988
			}
2989
		}
2990
		else
2991
		{
2992
			dol_print_error($this->db);
2993
			return -1;
2994
		}
2995
2996
		// We add the fullpath property to each elements of first level (no parent exists)
2997
		dol_syslog(get_class($this)."::get_full_tree call to build_path_from_id_user", LOG_DEBUG);
2998
		foreach($this->users as $key => $val)
2999
		{
3000
			$result = $this->build_path_from_id_user($key, 0);	// Process a branch from the root user key (this user has no parent)
3001
			if ($result < 0)
3002
			{
3003
				$this->error='ErrorLoopInHierarchy';
3004
				return -1;
3005
			}
3006
		}
3007
3008
		// Exclude leaf including $deleteafterid from tree
3009
		if ($deleteafterid)
3010
		{
3011
			//print "Look to discard user ".$deleteafterid."\n";
3012
			$keyfilter1='^'.$deleteafterid.'$';
3013
			$keyfilter2='_'.$deleteafterid.'$';
3014
			$keyfilter3='^'.$deleteafterid.'_';
3015
			$keyfilter4='_'.$deleteafterid.'_';
3016
			foreach($this->users as $key => $val)
3017
			{
3018
				if (preg_match('/'.$keyfilter1.'/', $val['fullpath']) || preg_match('/'.$keyfilter2.'/', $val['fullpath'])
3019
					|| preg_match('/'.$keyfilter3.'/', $val['fullpath']) || preg_match('/'.$keyfilter4.'/', $val['fullpath']))
3020
				{
3021
					unset($this->users[$key]);
3022
				}
3023
			}
3024
		}
3025
3026
		dol_syslog(get_class($this)."::get_full_tree dol_sort_array", LOG_DEBUG);
3027
		$this->users=dol_sort_array($this->users, 'fullname', 'asc', true, false);
3028
3029
		//var_dump($this->users);
3030
3031
		return $this->users;
3032
	}
3033
3034
	/**
3035
	 * 	Return list of all child users id in herarchy (all sublevels).
3036
	 *  Note: Calling this function also reset full list of users into $this->users.
3037
	 *
3038
	 *  @param      int      $addcurrentuser    1=Add also current user id to the list.
3039
	 *	@return		array		      		  	Array of user id lower than user (all levels under user). This overwrite this->users.
3040
	 *  @see get_children()
3041
	 */
3042
    public function getAllChildIds($addcurrentuser = 0)
3043
    {
3044
		$childids=array();
3045
3046
		if (isset($this->cache_childids[$this->id]))
3047
		{
3048
			$childids = $this->cache_childids[$this->id];
3049
		}
3050
		else
3051
		{
3052
			// Init this->users
3053
			$this->get_full_tree();
3054
3055
			$idtoscan=$this->id;
3056
3057
			dol_syslog("Build childid for id = ".$idtoscan);
3058
			foreach($this->users as $id => $val)
3059
			{
3060
				//var_dump($val['fullpath']);
3061
				if (preg_match('/_'.$idtoscan.'_/', $val['fullpath'])) $childids[$val['id']]=$val['id'];
3062
			}
3063
		}
3064
		$this->cache_childids[$this->id] = $childids;
3065
3066
		if ($addcurrentuser) $childids[$this->id]=$this->id;
3067
3068
		return $childids;
3069
	}
3070
3071
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3072
	/**
3073
	 *	For user id_user and its childs available in this->users, define property fullpath and fullname.
3074
	 *  Function called by get_full_tree().
3075
	 *
3076
	 * 	@param		int		$id_user		id_user entry to update
3077
	 * 	@param		int		$protection		Deep counter to avoid infinite loop (no more required, a protection is added with array useridfound)
3078
	 *	@return		int                     < 0 if KO (infinit loop), >= 0 if OK
3079
	 */
3080
    public function build_path_from_id_user($id_user, $protection = 0)
3081
    {
3082
        // phpcs:enable
3083
		dol_syslog(get_class($this)."::build_path_from_id_user id_user=".$id_user." protection=".$protection, LOG_DEBUG);
3084
3085
		if (! empty($this->users[$id_user]['fullpath']))
3086
		{
3087
			// Already defined
3088
			dol_syslog(get_class($this)."::build_path_from_id_user fullpath and fullname already defined", LOG_WARNING);
3089
			return 0;
3090
		}
3091
3092
		// Define fullpath and fullname
3093
		$this->users[$id_user]['fullpath'] = '_'.$id_user;
3094
		$this->users[$id_user]['fullname'] = $this->users[$id_user]['lastname'];
3095
		$i=0; $cursor_user=$id_user;
3096
3097
		$useridfound=array($id_user);
3098
		while (! empty($this->parentof[$cursor_user]))
3099
		{
3100
			if (in_array($this->parentof[$cursor_user], $useridfound))
3101
			{
3102
				dol_syslog("The hierarchy of user has a recursive loop", LOG_WARNING);
3103
				return -1;     // Should not happen. Protection against looping hierarchy
3104
			}
3105
			$useridfound[]=$this->parentof[$cursor_user];
3106
			$this->users[$id_user]['fullpath'] = '_'.$this->parentof[$cursor_user].$this->users[$id_user]['fullpath'];
3107
			$this->users[$id_user]['fullname'] = $this->users[$this->parentof[$cursor_user]]['lastname'].' >> '.$this->users[$id_user]['fullname'];
3108
			$i++; $cursor_user=$this->parentof[$cursor_user];
3109
		}
3110
3111
		// We count number of _ to have level
3112
		$this->users[$id_user]['level']=dol_strlen(preg_replace('/[^_]/i', '', $this->users[$id_user]['fullpath']));
3113
3114
		return 1;
3115
	}
3116
3117
	/**
3118
	 * Function used to replace a thirdparty id with another one.
3119
	 *
3120
	 * @param DoliDB $db Database handler
3121
	 * @param int $origin_id Old thirdparty id
3122
	 * @param int $dest_id New thirdparty id
3123
	 * @return bool
3124
	 */
3125
	public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
3126
	{
3127
		$tables = array(
3128
			'user',
3129
		);
3130
3131
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3132
	}
3133
3134
3135
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3136
	/**
3137
	 *      Load metrics this->nb for dashboard
3138
	 *
3139
	 *      @return     int         <0 if KO, >0 if OK
3140
	 */
3141
	public function load_state_board()
3142
	{
3143
        // phpcs:enable
3144
3145
		$this->nb=array();
3146
3147
		$sql = "SELECT count(u.rowid) as nb";
3148
		$sql.= " FROM ".MAIN_DB_PREFIX."user as u";
3149
		$sql.= " WHERE u.statut > 0";
3150
		//$sql.= " AND employee != 0";
3151
		$sql.= " AND u.entity IN (".getEntity('user').")";
3152
3153
		$resql=$this->db->query($sql);
3154
		if ($resql)
3155
		{
3156
			while ($obj=$this->db->fetch_object($resql))
3157
			{
3158
				$this->nb["users"]=$obj->nb;
3159
			}
3160
			$this->db->free($resql);
3161
			return 1;
3162
		}
3163
		else
3164
		{
3165
			dol_print_error($this->db);
3166
			$this->error=$this->db->error();
3167
			return -1;
3168
		}
3169
	}
3170
3171
	/**
3172
	 *  Create a document onto disk according to template module.
3173
	 *
3174
	 * 	@param	    string		$modele			Force model to use ('' to not force)
3175
	 * 	@param		Translate	$outputlangs	Object langs to use for output
3176
	 *  @param      int			$hidedetails    Hide details of lines
3177
	 *  @param      int			$hidedesc       Hide description
3178
	 *  @param      int			$hideref        Hide ref
3179
         *  @param   null|array  $moreparams     Array to provide more information
3180
	 * 	@return     int         				0 if KO, 1 if OK
3181
	 */
3182
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3183
	{
3184
		global $conf, $user, $langs;
3185
3186
		$langs->load("user");
3187
3188
		// Positionne le modele sur le nom du modele a utiliser
3189
		if (! dol_strlen($modele))
3190
		{
3191
			if (! empty($conf->global->USER_ADDON_PDF))
3192
			{
3193
				$modele = $conf->global->USER_ADDON_PDF;
3194
			}
3195
			else
3196
			{
3197
				$modele = 'bluesky';
3198
			}
3199
		}
3200
3201
		$modelpath = "core/modules/user/doc/";
3202
3203
		return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3204
	}
3205
3206
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3207
	/**
3208
	 *  Return property of user from its id
3209
	 *
3210
	 *  @param	int		$rowid      id of contact
3211
	 *  @param  string	$mode       'email' or 'mobile'
3212
	 *  @return string  			Email of user with format: "Full name <email>"
3213
	 */
3214
	public function user_get_property($rowid, $mode)
3215
	{
3216
        // phpcs:enable
3217
		$user_property='';
3218
3219
		if (empty($rowid)) return '';
3220
3221
		$sql = "SELECT rowid, email, user_mobile, civility, lastname, firstname";
3222
		$sql.= " FROM ".MAIN_DB_PREFIX."user";
3223
		$sql.= " WHERE rowid = '".$rowid."'";
3224
3225
		$resql=$this->db->query($sql);
3226
		if ($resql)
3227
		{
3228
			$nump = $this->db->num_rows($resql);
3229
3230
			if ($nump)
3231
			{
3232
				$obj = $this->db->fetch_object($resql);
3233
3234
				if ($mode == 'email') $user_property = dolGetFirstLastname($obj->firstname, $obj->lastname)." <".$obj->email.">";
3235
				elseif ($mode == 'mobile') $user_property = $obj->user_mobile;
3236
			}
3237
			return $user_property;
3238
		}
3239
		else
3240
		{
3241
			dol_print_error($this->db);
3242
		}
3243
	}
3244
3245
	/**
3246
	 *	Load all objects into $this->users
3247
	 *
3248
	 *  @param	string		$sortorder		sort order
3249
	 *  @param	string		$sortfield		sort field
3250
	 *  @param	int			$limit			limit page
3251
	 *  @param	int			$offset			page
3252
	 *  @param	array		$filter			Filter array. Example array('field'=>'valueforlike', 'customurl'=>...)
3253
	 *  @param  string      $filtermode		Filter mode (AND or OR)
3254
	 *  @param  bool        $entityfilter	Activate entity filter
3255
	 *  @return int							<0 if KO, >0 if OK
3256
	 */
3257
	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = array(), $filtermode = 'AND', $entityfilter = false)
3258
    {
3259
        global $conf, $user;
3260
3261
		$sql="SELECT t.rowid";
3262
		$sql.= ' FROM '.MAIN_DB_PREFIX .$this->table_element.' as t ';
3263
3264
		if ($entityfilter)
3265
		{
3266
			if (! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE))
3267
			{
3268
				if (! empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
3269
					$sql.= " WHERE t.entity IS NOT NULL"; // Show all users
3270
				} else {
3271
					$sql.= ",".MAIN_DB_PREFIX."usergroup_user as ug";
3272
					$sql.= " WHERE ((ug.fk_user = t.rowid";
3273
					$sql.= " AND ug.entity IN (".getEntity('user')."))";
3274
					$sql.= " OR t.entity = 0)"; // Show always superadmin
3275
				}
3276
			}
3277
			else
3278
			{
3279
				$sql.= " WHERE t.entity IN (".getEntity('user').")";
3280
			}
3281
		}
3282
		else
3283
		{
3284
			$sql.= " WHERE 1";
3285
		}
3286
3287
		// Manage filter
3288
		$sqlwhere = array();
3289
		if (!empty($filter)){
3290
			foreach($filter as $key => $value) {
3291
				if ($key=='t.rowid') {
3292
					$sqlwhere[] = $key . '='. $value;
3293
				}
3294
				elseif (strpos($key, 'date') !== false) {
3295
					$sqlwhere[] = $key.' = \''.$this->db->idate($value).'\'';
3296
				}
3297
				elseif ($key=='customsql') {
3298
					$sqlwhere[] = $value;
3299
				}
3300
				else {
3301
					$sqlwhere[] = $key . ' LIKE \'%' . $this->db->escape($value) . '%\'';
3302
				}
3303
			}
3304
		}
3305
		if (count($sqlwhere) > 0) {
3306
			$sql .= ' AND (' . implode(' '.$filtermode.' ', $sqlwhere).')';
3307
		}
3308
		$sql.= $this->db->order($sortfield, $sortorder);
3309
		if ($limit) $sql.= $this->db->plimit($limit+1, $offset);
3310
3311
		dol_syslog(get_class($this)."::".__METHOD__, LOG_DEBUG);
3312
3313
		$resql=$this->db->query($sql);
3314
		if ($resql)
3315
		{
3316
			$this->users=array();
3317
			$num = $this->db->num_rows($resql);
3318
			if ($num)
3319
			{
3320
				while ($obj = $this->db->fetch_object($resql))
3321
				{
3322
					$line = new self($this->db);
3323
					$result = $line->fetch($obj->rowid);
3324
					if ($result>0 && !empty($line->id)) {
3325
						$this->users[$obj->rowid] = clone $line;
3326
					}
3327
				}
3328
				$this->db->free($resql);
3329
			}
3330
			return $num;
3331
		}
3332
		else
3333
		{
3334
            $this->errors[] = $this->db->lasterror();
3335
            return -1;
3336
        }
3337
    }
3338
}
3339