Passed
Branch develop (07a336)
by
unknown
39:19
created

User::getNomUrl()   F

Complexity

Conditions 54
Paths 0

Size

Total Lines 164
Code Lines 107

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 54
eloc 107
nc 0
nop 9
dl 0
loc 164
rs 3.3333
c 1
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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-2020  Frédéric France         <[email protected]>
16
 * Copyright (C) 2019       Abbes Bahfir            <[email protected]>
17
 *
18
 * This program is free software; you can redistribute it and/or modify
19
 * it under the terms of the GNU General Public License as published by
20
 * the Free Software Foundation; either version 3 of the License, or
21
 * (at your option) any later version.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU General Public License
29
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
30
 */
31
32
/**
33
 *  \file       htdocs/user/class/user.class.php
34
 *	\brief      File of class to manage users
35
 *  \ingroup	core
36
 */
37
38
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
39
require_once DOL_DOCUMENT_ROOT.'/user/class/usergroup.class.php';
40
41
/**
42
 *	Class to manage Dolibarr users
43
 */
44
class User extends CommonObject
45
{
46
	/**
47
	 * @var string ID to identify managed object
48
	 */
49
	public $element = 'user';
50
51
	/**
52
	 * @var string Name of table without prefix where object is stored
53
	 */
54
	public $table_element = 'user';
55
56
	/**
57
	 * @var string Field with ID of parent key if this field has a parent
58
	 */
59
	public $fk_element = 'fk_user';
60
61
	/**
62
	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
63
	 * @var int
64
	 */
65
	public $ismultientitymanaged = 1;
66
67
	/**
68
	 * @var string picto
69
	 */
70
	public $picto = 'user';
71
72
	public $id = 0;
73
	public $statut;
74
	public $ldap_sid;
75
	public $search_sid;
76
	public $employee;
77
	public $civility_code;
78
79
	/**
80
	 * @var string gender
81
	 */
82
	public $gender;
83
	public $birth;
84
85
	/**
86
	 * @var string email
87
	 */
88
	public $email;
89
90
	/**
91
	 * @var string personal email
92
	 */
93
	public $personal_email;
94
95
	/**
96
	 * @var array array of socialnetworks
97
	 */
98
	public $socialnetworks;
99
100
	/**
101
	 * @var string skype account
102
	 * @deprecated
103
	 */
104
	public $skype;
105
106
	/**
107
	 * @var string twitter account
108
	 * @deprecated
109
	 */
110
	public $twitter;
111
112
	/**
113
	 * @var string facebook account
114
	 * @deprecated
115
	 */
116
	public $facebook;
117
118
	/**
119
	 * @var string linkedin account
120
	 * @deprecated
121
	 */
122
	public $linkedin;
123
124
	/**
125
	 * @var string job position
126
	 */
127
	public $job;
128
129
	/**
130
	 * @var string user signature
131
	 */
132
	public $signature;
133
134
	/**
135
	 * @var string Address
136
	 */
137
	public $address;
138
139
	/**
140
	 * @var string zip code
141
	 */
142
	public $zip;
143
144
	/**
145
	 * @var string town
146
	 */
147
	public $town;
148
	public $state_id; // The state/department
149
	public $state_code;
150
	public $state;
151
152
	/**
153
	 * @var string office phone
154
	 */
155
	public $office_phone;
156
157
	/**
158
	 * @var string office fax
159
	 */
160
	public $office_fax;
161
162
	/**
163
	 * @var string phone mobile
164
	 */
165
	public $user_mobile;
166
167
	/**
168
	 * @var string personal phone mobile
169
	 */
170
	public $personal_mobile;
171
172
	/**
173
	 * @var int 1 if admin 0 if standard user
174
	 */
175
	public $admin;
176
177
	/**
178
	 * @var string user login
179
	 */
180
	public $login;
181
182
	/**
183
	 * @var string user apikey
184
	 */
185
	public $api_key;
186
187
	/**
188
	 * @var int Entity
189
	 */
190
	public $entity;
191
192
	/**
193
	 * @var string Clear password in memory
194
	 */
195
	public $pass;
196
197
	/**
198
	 * @var string Clear password in database (defined if DATABASE_PWD_ENCRYPTED=0)
199
	 */
200
	public $pass_indatabase;
201
202
	/**
203
	 * @var string Encrypted password in database (always defined)
204
	 */
205
	public $pass_indatabase_crypted;
206
207
	/**
208
	 * @var string Temporary password
209
	 */
210
	public $pass_temp;
211
212
	/**
213
	 * Date creation record (datec)
214
	 *
215
	 * @var integer
216
	 */
217
	public $datec;
218
219
	/**
220
	 * Date modification record (tms)
221
	 *
222
	 * @var integer
223
	 */
224
	public $datem;
225
226
	/**
227
	 * @var int If this is defined, it is an external user
228
	 */
229
	public $socid;
230
231
	/**
232
	 * @var int If this is defined, it is a user created from a contact
233
	 */
234
	public $contact_id;
235
236
	/**
237
	 * @var int ID
238
	 */
239
	public $fk_member;
240
241
	/**
242
	 * @var int User ID of supervisor
243
	 */
244
	public $fk_user;
245
246
	/**
247
	 * @var int User ID of expense validator
248
	 */
249
	public $fk_user_expense_validator;
250
251
	/**
252
	 * @var int User ID of holidays validator
253
	 */
254
	public $fk_user_holiday_validator;
255
256
	/**
257
	 * @string clicktodial url
258
	 */
259
	public $clicktodial_url;
260
261
	/**
262
	 * @var string clicktodial login
263
	 */
264
	public $clicktodial_login;
265
266
	/**
267
	 * @var string clicktodial password
268
	 */
269
	public $clicktodial_password;
270
271
	/**
272
	 * @var string clicktodial poste
273
	 */
274
	public $clicktodial_poste;
275
276
	public $datelastlogin;
277
	public $datepreviouslogin;
278
	public $datestartvalidity;
279
	public $dateendvalidity;
280
281
	/**
282
	 * @var string photo filename
283
	 */
284
	public $photo;
285
	public $lang;
286
287
	/**
288
	 * @var stdClass Class of permissions user->rights->permx
289
	 */
290
	public $rights;
291
292
	/**
293
	 * @var int  All permissions are loaded
294
	 */
295
	public $all_permissions_are_loaded;
296
297
	/**
298
	 * @var int Number of rights granted to the user
299
	 */
300
	public $nb_rights;
301
302
	/**
303
	 * @var array Cache array of already loaded permissions
304
	 */
305
	private $_tab_loaded = array();
306
307
	/**
308
	 * @var stdClass To store personal config
309
	 */
310
	public $conf;
311
	public $default_values; // To store default values for user
312
	public $lastsearch_values_tmp; // To store current search criterias for user
313
	public $lastsearch_values; // To store last saved search criterias for user
314
315
	public $users = array(); // To store all tree of users hierarchy
316
	public $parentof; // To store an array of all parents for all ids.
317
	private $cache_childids; // Cache array of already loaded childs
318
319
	public $accountancy_code; // Accountancy code in prevision of the complete accountancy module
320
321
	public $thm; // Average cost of employee - Used for valuation of time spent
322
	public $tjm; // Average cost of employee
323
324
	public $salary; // Monthly salary       - Denormalized value from llx_user_employment
325
	public $salaryextra; // Monthly salary extra - Denormalized value from llx_user_employment
326
	public $weeklyhours; // Weekly hours         - Denormalized value from llx_user_employment
327
328
	/**
329
	 * @var string Define background color for user in agenda
330
	 */
331
	public $color;
332
333
	public $dateemployment; // Define date of employment by company
334
	public $dateemploymentend; // Define date of employment end by company
335
336
	public $default_c_exp_tax_cat;
337
	public $default_range;
338
339
	/**
340
	 *@var int id of warehouse
341
	 */
342
	public $fk_warehouse;
343
344
	public $fields = array(
345
		'rowid'=>array('type'=>'integer', 'label'=>'TechnicalID', 'enabled'=>1, 'visible'=>-2, 'notnull'=>1, 'index'=>1, 'position'=>1, 'comment'=>'Id'),
346
		'lastname'=>array('type'=>'varchar(50)', 'label'=>'Name', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>20, 'searchall'=>1),
347
		'firstname'=>array('type'=>'varchar(50)', 'label'=>'Name', 'enabled'=>1, 'visible'=>1, 'notnull'=>1, 'showoncombobox'=>1, 'index'=>1, 'position'=>10, 'searchall'=>1),
348
	);
349
350
351
	const STATUS_DISABLED = 0;
352
	const STATUS_ENABLED = 1;
353
354
355
356
	/**
357
	 *    Constructor of the class
358
	 *
359
	 *    @param   DoliDb  $db     Database handler
360
	 */
361
	public function __construct($db)
362
	{
363
		$this->db = $db;
364
365
		// User preference
366
		$this->liste_limit = 0;
367
		$this->clicktodial_loaded = 0;
368
369
		// For cache usage
370
		$this->all_permissions_are_loaded = 0;
371
		$this->nb_rights = 0;
372
373
		// Force some default values
374
		$this->admin = 0;
375
		$this->employee = 1;
376
377
		$this->conf = new stdClass();
378
		$this->rights = new stdClass();
379
		$this->rights->user = new stdClass();
380
		$this->rights->user->user = new stdClass();
381
		$this->rights->user->self = new stdClass();
382
	}
383
384
	/**
385
	 *	Load a user from database with its id or ref (login).
386
	 *  This function does not load permissions, only user properties. Use getrights() for this just after the fetch.
387
	 *
388
	 *	@param	int		$id		       		If defined, id to used for search
389
	 * 	@param  string	$login       		If defined, login to used for search
390
	 *	@param  string	$sid				If defined, sid to used for search
391
	 * 	@param	int		$loadpersonalconf	1=also load personal conf of user (in $user->conf->xxx), 0=do not load personal conf.
392
	 *  @param  int     $entity             If a value is >= 0, we force the search on a specific entity. If -1, means search depens on default setup.
393
	 *  @param	int		$email       		If defined, email to used for search
394
	 * 	@return	int							<0 if KO, 0 not found, >0 if OK
395
	 */
396
	public function fetch($id = '', $login = '', $sid = '', $loadpersonalconf = 0, $entity = -1, $email = '')
397
	{
398
		global $conf, $user;
399
400
		// Clean parameters
401
		$login = trim($login);
402
403
		// Get user
404
		$sql = "SELECT u.rowid, u.lastname, u.firstname, u.employee, u.gender, u.civility as civility_code, u.birth, u.email, u.personal_email, u.job,";
405
		$sql .= " u.socialnetworks,";
406
		$sql .= " u.signature, u.office_phone, u.office_fax, u.user_mobile, u.personal_mobile,";
407
		$sql .= " u.address, u.zip, u.town, u.fk_state as state_id, u.fk_country as country_id,";
408
		$sql .= " u.admin, u.login, u.note as note_private, u.note_public,";
409
		$sql .= " u.pass, u.pass_crypted, u.pass_temp, u.api_key,";
410
		$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,";
411
		$sql .= " u.statut, u.lang, u.entity,";
412
		$sql .= " u.datec as datec,";
413
		$sql .= " u.tms as datem,";
414
		$sql .= " u.datelastlogin as datel,";
415
		$sql .= " u.datepreviouslogin as datep,";
416
		$sql .= " u.datelastpassvalidation,";
417
		$sql .= " u.datestartvalidity,";
418
		$sql .= " u.dateendvalidity,";
419
		$sql .= " u.photo as photo,";
420
		$sql .= " u.openid as openid,";
421
		$sql .= " u.accountancy_code,";
422
		$sql .= " u.thm,";
423
		$sql .= " u.tjm,";
424
		$sql .= " u.salary,";
425
		$sql .= " u.salaryextra,";
426
		$sql .= " u.weeklyhours,";
427
		$sql .= " u.color,";
428
		$sql .= " u.dateemployment, u.dateemploymentend,";
429
		$sql .= " u.fk_warehouse,";
430
		$sql .= " u.ref_ext,";
431
		$sql .= " u.default_range, u.default_c_exp_tax_cat,"; // Expense report default mode
432
		$sql .= " c.code as country_code, c.label as country,";
433
		$sql .= " d.code_departement as state_code, d.nom as state";
434
		$sql .= " FROM ".MAIN_DB_PREFIX."user as u";
435
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON u.fk_country = c.rowid";
436
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as d ON u.fk_state = d.rowid";
437
438
		if ($entity < 0) {
439
			if ((empty($conf->multicompany->enabled) || empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) && (!empty($user->entity))) {
440
				$sql .= " WHERE u.entity IN (0,".$conf->entity.")";
441
			} else {
442
				$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
443
			}
444
		} else {
445
			// The fetch was forced on an entity
446
			if (!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
447
				$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
448
			} else {
449
				$sql .= " WHERE u.entity IN (0, ".(($entity != '' && $entity >= 0) ? $entity : $conf->entity).")"; // search in entity provided in parameter
450
			}
451
		}
452
453
		if ($sid) {    // permet une recherche du user par son SID ActiveDirectory ou Samba
454
			$sql .= " AND (u.ldap_sid = '".$this->db->escape($sid)."' OR u.login = '".$this->db->escape($login)."') LIMIT 1";
455
		} elseif ($login) {
456
			$sql .= " AND u.login = '".$this->db->escape($login)."'";
457
		} elseif ($email) {
458
			$sql .= " AND u.email = '".$this->db->escape($email)."'";
459
		} else {
460
			$sql .= " AND u.rowid = ".$id;
461
		}
462
		$sql .= " ORDER BY u.entity ASC"; // Avoid random result when there is 2 login in 2 different entities
463
464
		$result = $this->db->query($sql);
465
		if ($result) {
466
			$obj = $this->db->fetch_object($result);
467
			if ($obj) {
468
				$this->id = $obj->rowid;
469
				$this->ref = $obj->rowid;
470
471
				$this->ref_ext = $obj->ref_ext;
472
473
				$this->ldap_sid = $obj->ldap_sid;
474
				$this->civility_code = $obj->civility_code;
475
				$this->lastname = $obj->lastname;
476
				$this->firstname = $obj->firstname;
477
478
				$this->employee = $obj->employee;
479
480
				$this->login = $obj->login;
481
				$this->gender       = $obj->gender;
482
				$this->birth        = $this->db->jdate($obj->birth);
483
				$this->pass_indatabase = $obj->pass;
484
				$this->pass_indatabase_crypted = $obj->pass_crypted;
485
				$this->pass = $obj->pass;
486
				$this->pass_temp	= $obj->pass_temp;
487
				$this->api_key = $obj->api_key;
488
489
				$this->address 		= $obj->address;
490
				$this->zip 			= $obj->zip;
491
				$this->town 		= $obj->town;
492
493
				$this->country_id = $obj->country_id;
494
				$this->country_code = $obj->country_id ? $obj->country_code : '';
495
				//$this->country = $obj->country_id?($langs->trans('Country'.$obj->country_code)!='Country'.$obj->country_code?$langs->transnoentities('Country'.$obj->country_code):$obj->country):'';
496
497
				$this->state_id     = $obj->state_id;
498
				$this->state_code   = $obj->state_code;
499
				$this->state        = ($obj->state != '-' ? $obj->state : '');
500
501
				$this->office_phone	= $obj->office_phone;
502
				$this->office_fax   = $obj->office_fax;
503
				$this->user_mobile  = $obj->user_mobile;
504
				$this->personal_mobile = $obj->personal_mobile;
505
				$this->email = $obj->email;
506
				$this->personal_email = $obj->personal_email;
507
				$this->socialnetworks = (array) json_decode($obj->socialnetworks, true);
508
				$this->job = $obj->job;
509
				$this->signature = $obj->signature;
510
				$this->admin		= $obj->admin;
511
				$this->note_public = $obj->note_public;
512
				$this->note_private = $obj->note_private;
513
				$this->note			= $obj->note_private;
514
				$this->statut		= $obj->statut;
515
				$this->photo		= $obj->photo;
516
				$this->openid		= $obj->openid;
517
				$this->lang			= $obj->lang;
518
				$this->entity		= $obj->entity;
519
				$this->accountancy_code = $obj->accountancy_code;
520
				$this->thm			= $obj->thm;
521
				$this->tjm			= $obj->tjm;
522
				$this->salary = $obj->salary;
523
				$this->salaryextra = $obj->salaryextra;
524
				$this->weeklyhours = $obj->weeklyhours;
525
				$this->color = $obj->color;
526
				$this->dateemployment = $this->db->jdate($obj->dateemployment);
527
				$this->dateemploymentend = $this->db->jdate($obj->dateemploymentend);
528
529
				$this->datec				= $this->db->jdate($obj->datec);
530
				$this->datem				= $this->db->jdate($obj->datem);
531
				$this->datelastlogin = $this->db->jdate($obj->datel);
532
				$this->datepreviouslogin = $this->db->jdate($obj->datep);
533
				$this->datestartvalidity = $this->db->jdate($obj->datestartvalidity);
534
				$this->dateendvalidity = $this->db->jdate($obj->dateendvalidity);
535
536
				$this->socid                = $obj->fk_soc;
537
				$this->contact_id           = $obj->fk_socpeople;
538
				$this->fk_member            = $obj->fk_member;
539
				$this->fk_user = $obj->fk_user;
540
				$this->fk_user_expense_validator = $obj->fk_user_expense_validator;
541
				$this->fk_user_holiday_validator = $obj->fk_user_holiday_validator;
542
543
				$this->default_range = $obj->default_range;
544
				$this->default_c_exp_tax_cat = $obj->default_c_exp_tax_cat;
545
				$this->fk_warehouse = $obj->fk_warehouse;
546
547
				// Protection when module multicompany was set, admin was set to first entity and then, the module was disabled,
548
				// in such case, this admin user must be admin for ALL entities.
549
				if (empty($conf->multicompany->enabled) && $this->admin && $this->entity == 1) {
550
					$this->entity = 0;
551
				}
552
553
				// Retrieve all extrafield
554
				// fetch optionals attributes and labels
555
				$this->fetch_optionals();
556
557
				$this->db->free($result);
558
			} else {
559
				$this->error = "USERNOTFOUND";
560
				dol_syslog(get_class($this)."::fetch user not found", LOG_DEBUG);
561
562
				$this->db->free($result);
563
				return 0;
564
			}
565
		} else {
566
			$this->error = $this->db->lasterror();
567
			return -1;
568
		}
569
570
		// To get back the global configuration unique to the user
571
		if ($loadpersonalconf) {
572
			// Load user->conf for user
573
			$sql = "SELECT param, value FROM ".MAIN_DB_PREFIX."user_param";
574
			$sql .= " WHERE fk_user = ".$this->id;
575
			$sql .= " AND entity = ".$conf->entity;
576
			//dol_syslog(get_class($this).'::fetch load personalized conf', LOG_DEBUG);
577
			$resql = $this->db->query($sql);
578
			if ($resql) {
579
				$num = $this->db->num_rows($resql);
580
				$i = 0;
581
				while ($i < $num) {
582
					$obj = $this->db->fetch_object($resql);
583
					$p = (!empty($obj->param) ? $obj->param : '');
584
					if (!empty($p)) {
585
						$this->conf->$p = $obj->value;
586
					}
587
					$i++;
588
				}
589
				$this->db->free($resql);
590
			} else {
591
				$this->error = $this->db->lasterror();
592
				return -2;
593
			}
594
595
			$result = $this->loadDefaultValues();
596
597
			if ($result < 0) {
598
				$this->error = $this->db->lasterror();
599
				return -3;
600
			}
601
		}
602
603
		return 1;
604
	}
605
606
	/**
607
	 *  Load default value in property ->default_values
608
	 *
609
	 *  @return int						> 0 if OK, < 0 if KO
610
	 */
611
	public function loadDefaultValues()
612
	{
613
		global $conf;
614
615
		// Load user->default_values for user. TODO Save this in memcached ?
616
		$sql = "SELECT rowid, entity, type, page, param, value";
617
		$sql .= " FROM ".MAIN_DB_PREFIX."default_values";
618
		$sql .= " WHERE entity IN (".($this->entity > 0 ? $this->entity.", " : "").$conf->entity.")"; // Entity of user (if defined) + current entity
619
		$sql .= " AND user_id IN (0".($this->id > 0 ? ", ".$this->id : "").")"; // User 0 (all) + me (if defined)
620
		$resql = $this->db->query($sql);
621
		if ($resql) {
622
			while ($obj = $this->db->fetch_object($resql)) {
623
				if (!empty($obj->page) && !empty($obj->type) && !empty($obj->param)) {
624
					// $obj->page is relative URL with or without params
625
					// $obj->type can be 'filters', 'sortorder', 'createform', ...
626
					// $obj->param is key or param
627
					$pagewithoutquerystring = $obj->page;
628
					$pagequeries = '';
629
					$reg = array();
630
					if (preg_match('/^([^\?]+)\?(.*)$/', $pagewithoutquerystring, $reg)) {	// There is query param
631
						$pagewithoutquerystring = $reg[1];
632
						$pagequeries = $reg[2];
633
					}
634
					$this->default_values[$pagewithoutquerystring][$obj->type][$pagequeries ? $pagequeries : '_noquery_'][$obj->param] = $obj->value;
635
					//if ($pagequeries) $this->default_values[$pagewithoutquerystring][$obj->type.'_queries']=$pagequeries;
636
				}
637
			}
638
			// Sort by key, so _noquery_ is last
639
			if (!empty($this->default_values)) {
640
				foreach ($this->default_values as $a => $b) {
641
					foreach ($b as $c => $d) {
642
						krsort($this->default_values[$a][$c]);
643
					}
644
				}
645
			}
646
			$this->db->free($resql);
647
648
			return 1;
649
		} else {
650
			dol_print_error($this->db);
651
			return -1;
652
		}
653
	}
654
655
	/**
656
	 *  Add a right to the user
657
	 *
658
	 * 	@param	int		$rid			Id of permission to add or 0 to add several permissions
659
	 *  @param  string	$allmodule		Add all permissions of module $allmodule or 'allmodules' to include all modules.
660
	 *  @param  string	$allperms		Add all permissions of module $allmodule, subperms $allperms only or '' to include all permissions.
661
	 *  @param	int		$entity			Entity to use
662
	 *  @param  int	    $notrigger		1=Does not execute triggers, 0=Execute triggers
663
	 *  @return int						> 0 if OK, < 0 if KO
664
	 *  @see	clearrights(), delrights(), getrights()
665
	 */
666
	public function addrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
667
	{
668
		global $conf, $user, $langs;
669
670
		$entity = (!empty($entity) ? $entity : $conf->entity);
671
672
		dol_syslog(get_class($this)."::addrights $rid, $allmodule, $allperms, $entity");
673
		$error = 0;
674
		$whereforadd = '';
675
676
		$this->db->begin();
677
678
		if (!empty($rid)) {
679
			$module = $perms = $subperms = '';
680
681
			// Si on a demande ajout d'un droit en particulier, on recupere
682
			// les caracteristiques (module, perms et subperms) de ce droit.
683
			$sql = "SELECT module, perms, subperms";
684
			$sql .= " FROM ".MAIN_DB_PREFIX."rights_def";
685
			$sql .= " WHERE id = ".((int) $rid);
686
			$sql .= " AND entity = ".((int) $entity);
687
688
			$result = $this->db->query($sql);
689
			if ($result) {
690
				$obj = $this->db->fetch_object($result);
691
692
				if ($obj) {
693
					$module = $obj->module;
694
					$perms = $obj->perms;
695
					$subperms = $obj->subperms;
696
				}
697
			} else {
698
				$error++;
699
				dol_print_error($this->db);
700
			}
701
702
			// Where pour la liste des droits a ajouter
703
			$whereforadd = "id=".((int) $rid);
704
			// Ajout des droits induits
705
			if (!empty($subperms)) {
706
				$whereforadd .= " OR (module='".$this->db->escape($module)."' AND perms='".$this->db->escape($perms)."' AND (subperms='lire' OR subperms='read'))";
707
			} elseif (!empty($perms)) {
708
				$whereforadd .= " OR (module='".$this->db->escape($module)."' AND (perms='lire' OR perms='read') AND subperms IS NULL)";
709
			}
710
		} else {
711
			// On a pas demande un droit en particulier mais une liste de droits
712
			// sur la base d'un nom de module de de perms
713
			// Where pour la liste des droits a ajouter
714
			if (!empty($allmodule)) {
715
				if ($allmodule == 'allmodules') {
716
					$whereforadd = 'allmodules';
717
				} else {
718
					$whereforadd = "module='".$this->db->escape($allmodule)."'";
719
					if (!empty($allperms)) {
720
						$whereforadd .= " AND perms='".$this->db->escape($allperms)."'";
721
					}
722
				}
723
			}
724
		}
725
726
		// Ajout des droits trouves grace au critere whereforadd
727
		if (!empty($whereforadd)) {
728
			//print "$module-$perms-$subperms";
729
			$sql = "SELECT id";
730
			$sql .= " FROM ".MAIN_DB_PREFIX."rights_def";
731
			$sql .= " WHERE entity = ".$entity;
732
			if (!empty($whereforadd) && $whereforadd != 'allmodules') {
733
				$sql .= " AND ".$whereforadd;
734
			}
735
736
			$result = $this->db->query($sql);
737
			if ($result) {
738
				$num = $this->db->num_rows($result);
739
				$i = 0;
740
				while ($i < $num) {
741
					$obj = $this->db->fetch_object($result);
742
					$nid = $obj->id;
743
744
					$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights WHERE fk_user = ".$this->id." AND fk_id=".$nid." AND entity = ".$entity;
745
					if (!$this->db->query($sql)) {
746
						$error++;
747
					}
748
					$sql = "INSERT INTO ".MAIN_DB_PREFIX."user_rights (entity, fk_user, fk_id) VALUES (".$entity.", ".$this->id.", ".$nid.")";
749
					if (!$this->db->query($sql)) {
750
						$error++;
751
					}
752
753
					$i++;
754
				}
755
			} else {
756
				$error++;
757
				dol_print_error($this->db);
758
			}
759
		}
760
761
		if (!$error && !$notrigger) {
762
			$langs->load("other");
763
			$this->context = array('audit'=>$langs->trans("PermissionsAdd").($rid ? ' (id='.$rid.')' : ''));
764
765
			// Call trigger
766
			$result = $this->call_trigger('USER_MODIFY', $user);
767
			if ($result < 0) {
768
				$error++;
769
			}
770
			// End call triggers
771
		}
772
773
		if ($error) {
774
			$this->db->rollback();
775
			return -$error;
776
		} else {
777
			$this->db->commit();
778
			return 1;
779
		}
780
	}
781
782
783
	/**
784
	 *  Remove a right to the user
785
	 *
786
	 *  @param	int		$rid        Id du droit a retirer
787
	 *  @param  string	$allmodule  Retirer tous les droits du module allmodule
788
	 *  @param  string	$allperms   Retirer tous les droits du module allmodule, perms allperms
789
	 *  @param	int		$entity		Entity to use
790
	 *  @param  int	    $notrigger	1=Does not execute triggers, 0=Execute triggers
791
	 *  @return int         		> 0 if OK, < 0 if OK
792
	 *  @see	clearrights(), addrights(), getrights()
793
	 */
794
	public function delrights($rid, $allmodule = '', $allperms = '', $entity = 0, $notrigger = 0)
795
	{
796
		global $conf, $user, $langs;
797
798
		$error = 0;
799
		$wherefordel = '';
800
		$entity = (!empty($entity) ? $entity : $conf->entity);
801
802
		$this->db->begin();
803
804
		if (!empty($rid)) {
805
			$module = $perms = $subperms = '';
806
807
			// Si on a demande supression d'un droit en particulier, on recupere
808
			// les caracteristiques module, perms et subperms de ce droit.
809
			$sql = "SELECT module, perms, subperms";
810
			$sql .= " FROM ".MAIN_DB_PREFIX."rights_def";
811
			$sql .= " WHERE id = '".$this->db->escape($rid)."'";
812
			$sql .= " AND entity = ".$entity;
813
814
			$result = $this->db->query($sql);
815
			if ($result) {
816
				$obj = $this->db->fetch_object($result);
817
818
				if ($obj) {
819
					$module = $obj->module;
820
					$perms = $obj->perms;
821
					$subperms = $obj->subperms;
822
				}
823
			} else {
824
				$error++;
825
				dol_print_error($this->db);
826
			}
827
828
			// Where pour la liste des droits a supprimer
829
			$wherefordel = "id=".((int) $rid);
830
			// Suppression des droits induits
831
			if ($subperms == 'lire' || $subperms == 'read') {
0 ignored issues
show
introduced by
The condition $subperms == 'read' is always false.
Loading history...
832
				$wherefordel .= " OR (module='".$this->db->escape($module)."' AND perms='".$this->db->escape($perms)."' AND subperms IS NOT NULL)";
833
			}
834
			if ($perms == 'lire' || $perms == 'read') {
0 ignored issues
show
introduced by
The condition $perms == 'read' is always false.
Loading history...
835
				$wherefordel .= " OR (module='".$this->db->escape($module)."')";
836
			}
837
		} else {
838
			// On a demande suppression d'un droit sur la base d'un nom de module ou perms
839
			// Where pour la liste des droits a supprimer
840
			if (!empty($allmodule)) {
841
				if ($allmodule == 'allmodules') {
842
					$wherefordel = 'allmodules';
843
				} else {
844
					$wherefordel = "module='".$this->db->escape($allmodule)."'";
845
					if (!empty($allperms)) {
846
						$wherefordel .= " AND perms='".$this->db->escape($allperms)."'";
847
					}
848
				}
849
			}
850
		}
851
852
		// Suppression des droits selon critere defini dans wherefordel
853
		if (!empty($wherefordel)) {
854
			//print "$module-$perms-$subperms";
855
			$sql = "SELECT id";
856
			$sql .= " FROM ".MAIN_DB_PREFIX."rights_def";
857
			$sql .= " WHERE entity = ".$entity;
858
			if (!empty($wherefordel) && $wherefordel != 'allmodules') {
859
				$sql .= " AND ".$wherefordel;
860
			}
861
862
			// avoid admin can remove his own important rights
863
			if ($this->admin == 1) {
864
				$sql .= " AND id NOT IN (251, 252, 253, 254, 255, 256)"; // other users rights
865
				$sql .= " AND id NOT IN (341, 342, 343, 344)"; // own rights
866
				$sql .= " AND id NOT IN (351, 352, 353, 354)"; // groups rights
867
				$sql .= " AND id NOT IN (358)"; // user export
868
			}
869
870
			$result = $this->db->query($sql);
871
			if ($result) {
872
				$num = $this->db->num_rows($result);
873
				$i = 0;
874
				while ($i < $num) {
875
					$obj = $this->db->fetch_object($result);
876
					$nid = $obj->id;
877
878
					$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights";
879
					$sql .= " WHERE fk_user = ".$this->id." AND fk_id=".$nid;
880
					$sql .= " AND entity = ".$entity;
881
					if (!$this->db->query($sql)) {
882
						$error++;
883
					}
884
885
					$i++;
886
				}
887
			} else {
888
				$error++;
889
				dol_print_error($this->db);
890
			}
891
		}
892
893
		if (!$error && !$notrigger) {
894
			$langs->load("other");
895
			$this->context = array('audit'=>$langs->trans("PermissionsDelete").($rid ? ' (id='.$rid.')' : ''));
896
897
			// Call trigger
898
			$result = $this->call_trigger('USER_MODIFY', $user);
899
			if ($result < 0) {
900
				$error++;
901
			}
902
			// End call triggers
903
		}
904
905
		if ($error) {
906
			$this->db->rollback();
907
			return -$error;
908
		} else {
909
			$this->db->commit();
910
			return 1;
911
		}
912
	}
913
914
915
	/**
916
	 *  Clear all permissions array of user
917
	 *
918
	 *  @return	void
919
	 *  @see	getrights()
920
	 */
921
	public function clearrights()
922
	{
923
		dol_syslog(get_class($this)."::clearrights reset user->rights");
924
		$this->rights = null;
925
		$this->nb_rights = 0;
926
		$this->all_permissions_are_loaded = 0;
927
		$this->_tab_loaded = array();
928
	}
929
930
931
	/**
932
	 *	Load permissions granted to user into object user
933
	 *
934
	 *	@param  string	$moduletag		Limit permission for a particular module ('' by default means load all permissions)
935
	 *  @param	int		$forcereload	Force reload of permissions even if they were already loaded (ignore cache)
936
	 *	@return	void
937
	 *  @see	clearrights(), delrights(), addrights()
938
	 */
939
	public function getrights($moduletag = '', $forcereload = 0)
940
	{
941
		global $conf;
942
943
		if (empty($forcereload)) {
944
			if ($moduletag && isset($this->_tab_loaded[$moduletag]) && $this->_tab_loaded[$moduletag]) {
945
				// Rights for this module are already loaded, so we leave
946
				return;
947
			}
948
949
			if (!empty($this->all_permissions_are_loaded)) {
950
				// We already loaded all rights for this user, so we leave
951
				return;
952
			}
953
		}
954
955
		// Get permission of users + Get permissions of groups
956
957
		// First user permissions
958
		$sql = "SELECT DISTINCT r.module, r.perms, r.subperms";
959
		$sql .= " FROM ".MAIN_DB_PREFIX."user_rights as ur";
960
		$sql .= ", ".MAIN_DB_PREFIX."rights_def as r";
961
		$sql .= " WHERE r.id = ur.fk_id";
962
		if (!empty($conf->global->MULTICOMPANY_BACKWARD_COMPATIBILITY)) {
963
			$sql .= " AND r.entity IN (0,".(!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) ? "1," : "").$conf->entity.")";
964
		} else {
965
			$sql .= " AND ur.entity = ".$conf->entity;
966
		}
967
		$sql .= " AND ur.fk_user= ".$this->id;
968
		$sql .= " AND r.perms IS NOT NULL";
969
		if ($moduletag) {
970
			$sql .= " AND r.module = '".$this->db->escape($moduletag)."'";
971
		}
972
973
		$resql = $this->db->query($sql);
974
		if ($resql) {
975
			$num = $this->db->num_rows($resql);
976
			$i = 0;
977
978
			while ($i < $num) {
979
				$obj = $this->db->fetch_object($resql);
980
981
				if ($obj) {
982
					$module = $obj->module;
983
					$perms = $obj->perms;
984
					$subperms = $obj->subperms;
985
986
					if (!empty($perms)) {
987
						if (!isset($this->rights) || !is_object($this->rights)) {
988
							$this->rights = new stdClass(); // For avoid error
989
						}
990
						if (!empty($module)) {
991
							if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
992
								$this->rights->$module = new stdClass();
993
							}
994
							if (!empty($subperms)) {
995
								if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
996
									$this->rights->$module->$perms = new stdClass();
997
								}
998
								if (empty($this->rights->$module->$perms->$subperms)) {
999
									$this->nb_rights++;
1000
								}
1001
								$this->rights->$module->$perms->$subperms = 1;
1002
							} else {
1003
								if (empty($this->rights->$module->$perms)) {
1004
									$this->nb_rights++;
1005
								}
1006
								$this->rights->$module->$perms = 1;
1007
							}
1008
						}
1009
					}
1010
				}
1011
				$i++;
1012
			}
1013
			$this->db->free($resql);
1014
		}
1015
1016
		// Now permissions of groups
1017
		$sql = "SELECT DISTINCT r.module, r.perms, r.subperms";
1018
		$sql .= " FROM ".MAIN_DB_PREFIX."usergroup_rights as gr,";
1019
		$sql .= " ".MAIN_DB_PREFIX."usergroup_user as gu,";
1020
		$sql .= " ".MAIN_DB_PREFIX."rights_def as r";
1021
		$sql .= " WHERE r.id = gr.fk_id";
1022
		if (!empty($conf->global->MULTICOMPANY_BACKWARD_COMPATIBILITY)) {
1023
			if (!empty($conf->multicompany->enabled) && !empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
1024
				$sql .= " AND gu.entity IN (0,".$conf->entity.")";
1025
			} else {
1026
				$sql .= " AND r.entity = ".$conf->entity;
1027
			}
1028
		} else {
1029
			$sql .= " AND gr.entity = ".$conf->entity;
1030
			$sql .= " AND gu.entity = ".$conf->entity;
1031
			$sql .= " AND r.entity = ".$conf->entity;
1032
		}
1033
		$sql .= " AND gr.fk_usergroup = gu.fk_usergroup";
1034
		$sql .= " AND gu.fk_user = ".$this->id;
1035
		$sql .= " AND r.perms IS NOT NULL";
1036
		if ($moduletag) {
1037
			$sql .= " AND r.module = '".$this->db->escape($moduletag)."'";
1038
		}
1039
1040
		$resql = $this->db->query($sql);
1041
		if ($resql) {
1042
			$num = $this->db->num_rows($resql);
1043
			$i = 0;
1044
			while ($i < $num) {
1045
				$obj = $this->db->fetch_object($resql);
1046
1047
				if ($obj) {
1048
					$module = $obj->module;
1049
					$perms = $obj->perms;
1050
					$subperms = $obj->subperms;
1051
1052
					if (!empty($perms)) {
1053
						if (!isset($this->rights) || !is_object($this->rights)) {
1054
							$this->rights = new stdClass(); // For avoid error
1055
						}
1056
						if (!empty($module)) {
1057
							if (!isset($this->rights->$module) || !is_object($this->rights->$module)) {
1058
								$this->rights->$module = new stdClass();
1059
							}
1060
							if (!empty($subperms)) {
1061
								if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1062
									$this->rights->$module->$perms = new stdClass();
1063
								}
1064
								if (empty($this->rights->$module->$perms->$subperms)) {
1065
									$this->nb_rights++;
1066
								}
1067
								$this->rights->$module->$perms->$subperms = 1;
1068
							} else {
1069
								if (empty($this->rights->$module->$perms)) {
1070
									$this->nb_rights++;
1071
								}
1072
								// 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
1073
								if (!isset($this->rights->$module->$perms) || !is_object($this->rights->$module->$perms)) {
1074
									$this->rights->$module->$perms = 1;
1075
								}
1076
							}
1077
						}
1078
					}
1079
				}
1080
				$i++;
1081
			}
1082
			$this->db->free($resql);
1083
		}
1084
1085
		// For backward compatibility
1086
		if (isset($this->rights->propale) && !isset($this->rights->propal)) {
1087
			$this->rights->propal = $this->rights->propale;
1088
		}
1089
		if (isset($this->rights->propal) && !isset($this->rights->propale)) {
1090
			$this->rights->propale = $this->rights->propal;
1091
		}
1092
1093
		if (!$moduletag) {
1094
			// Si module etait non defini, alors on a tout charge, on peut donc considerer
1095
			// que les droits sont en cache (car tous charges) pour cet instance de user
1096
			$this->all_permissions_are_loaded = 1;
1097
		} else {
1098
			// If module defined, we flag it as loaded into cache
1099
			$this->_tab_loaded[$moduletag] = 1;
1100
		}
1101
	}
1102
1103
	/**
1104
	 *  Change status of a user
1105
	 *
1106
	 *	@param	int		$status		Status to set
1107
	 *  @return int     			<0 if KO, 0 if nothing is done, >0 if OK
1108
	 */
1109
	public function setstatus($status)
1110
	{
1111
		global $conf, $langs, $user;
1112
1113
		$error = 0;
1114
1115
		// Check parameters
1116
		if ($this->statut == $status) {
1117
			return 0;
1118
		} else {
1119
			$this->statut = $status;
1120
		}
1121
1122
		$this->db->begin();
1123
1124
		// Save in database
1125
		$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1126
		$sql .= " SET statut = ".$this->statut;
1127
		$sql .= " WHERE rowid = ".$this->id;
1128
		$result = $this->db->query($sql);
1129
1130
		dol_syslog(get_class($this)."::setstatus", LOG_DEBUG);
1131
		if ($result) {
1132
			// Call trigger
1133
			$result = $this->call_trigger('USER_ENABLEDISABLE', $user);
1134
			if ($result < 0) {
1135
				$error++;
1136
			}
1137
			// End call triggers
1138
		}
1139
1140
		if ($error) {
1141
			$this->db->rollback();
1142
			return -$error;
1143
		} else {
1144
			$this->db->commit();
1145
			return 1;
1146
		}
1147
	}
1148
1149
	/**
1150
	 * Sets object to supplied categories.
1151
	 *
1152
	 * Deletes object from existing categories not supplied.
1153
	 * Adds it to non existing supplied categories.
1154
	 * Existing categories are left untouch.
1155
	 *
1156
	 * @param int[]|int $categories Category or categories IDs
1157
	 * @return void
1158
	 */
1159
	public function setCategories($categories)
1160
	{
1161
		require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
1162
		return parent::setCategoriesCommon($categories, Categorie::TYPE_USER);
1163
	}
1164
1165
	/**
1166
	 *  Delete the user
1167
	 *
1168
	 *	@param		User	$user	User than delete
1169
	 * 	@return		int				<0 if KO, >0 if OK
1170
	 */
1171
	public function delete(User $user)
1172
	{
1173
		global $conf, $langs;
1174
1175
		$error = 0;
1176
1177
		$this->db->begin();
1178
1179
		$this->fetch($this->id);
1180
1181
		dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1182
1183
		// Remove rights
1184
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights WHERE fk_user = ".$this->id;
1185
1186
		if (!$error && !$this->db->query($sql)) {
1187
			$error++;
1188
			$this->error = $this->db->lasterror();
1189
		}
1190
1191
		// Remove group
1192
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."usergroup_user WHERE fk_user  = ".$this->id;
1193
		if (!$error && !$this->db->query($sql)) {
1194
			$error++;
1195
			$this->error = $this->db->lasterror();
1196
		}
1197
1198
		// Remove params
1199
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param WHERE fk_user  = ".$this->id;
1200
		if (!$error && !$this->db->query($sql)) {
1201
			$error++;
1202
			$this->error = $this->db->lasterror();
1203
		}
1204
1205
		// If contact, remove link
1206
		if ($this->contact_id > 0) {
1207
			$sql = "UPDATE ".MAIN_DB_PREFIX."socpeople SET fk_user_creat = null WHERE rowid = ".$this->contact_id;
1208
			if (!$error && !$this->db->query($sql)) {
1209
				$error++;
1210
				$this->error = $this->db->lasterror();
1211
			}
1212
		}
1213
1214
		// Remove extrafields
1215
		if (!$error) {
1216
			$result = $this->deleteExtraFields();
1217
			if ($result < 0) {
1218
				$error++;
1219
				dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
1220
			}
1221
		}
1222
1223
		// Remove user
1224
		if (!$error) {
1225
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."user WHERE rowid = ".$this->id;
1226
			dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1227
			if (!$this->db->query($sql)) {
1228
				$error++;
1229
				$this->error = $this->db->lasterror();
1230
			}
1231
		}
1232
1233
		if (!$error) {
1234
			// Call trigger
1235
			$result = $this->call_trigger('USER_DELETE', $user);
1236
			if ($result < 0) {
1237
				$error++;
1238
				$this->db->rollback();
1239
				return -1;
1240
			}
1241
			// End call triggers
1242
1243
			$this->db->commit();
1244
			return 1;
1245
		} else {
1246
			$this->db->rollback();
1247
			return -1;
1248
		}
1249
	}
1250
1251
	/**
1252
	 *  Create a user into database
1253
	 *
1254
	 *  @param	User	$user        	Objet user doing creation
1255
	 *  @param  int		$notrigger		1=do not execute triggers, 0 otherwise
1256
	 *  @return int			         	<0 if KO, id of created user if OK
1257
	 */
1258
	public function create($user, $notrigger = 0)
1259
	{
1260
		global $conf, $langs;
1261
		global $mysoc;
1262
1263
		// Clean parameters
1264
		$this->setUpperOrLowerCase();
1265
1266
		$this->civility_code = trim($this->civility_code);
1267
		$this->login = trim($this->login);
1268
		if (!isset($this->entity)) {
1269
			$this->entity = $conf->entity; // If not defined, we use default value
1270
		}
1271
1272
		dol_syslog(get_class($this)."::create login=".$this->login.", user=".(is_object($user) ? $user->id : ''), LOG_DEBUG);
1273
1274
		// Check parameters
1275
		if (!empty($conf->global->USER_MAIL_REQUIRED) && !isValidEMail($this->email)) {
1276
			$langs->load("errors");
1277
			$this->error = $langs->trans("ErrorBadEMail", $this->email);
1278
			return -1;
1279
		}
1280
		if (empty($this->login)) {
1281
			$langs->load("errors");
1282
			$this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Login"));
1283
			return -1;
1284
		}
1285
1286
		$this->datec = dol_now();
1287
1288
		$error = 0;
1289
		$this->db->begin();
1290
1291
		$sql = "SELECT login FROM ".MAIN_DB_PREFIX."user";
1292
		$sql .= " WHERE login ='".$this->db->escape($this->login)."'";
1293
		$sql .= " AND entity IN (0,".$this->db->escape($conf->entity).")";
1294
1295
		dol_syslog(get_class($this)."::create", LOG_DEBUG);
1296
		$resql = $this->db->query($sql);
1297
		if ($resql) {
1298
			$num = $this->db->num_rows($resql);
1299
			$this->db->free($resql);
1300
1301
			if ($num) {
1302
				$this->error = 'ErrorLoginAlreadyExists';
1303
				dol_syslog(get_class($this)."::create ".$this->error, LOG_WARNING);
1304
				$this->db->rollback();
1305
				return -6;
1306
			} else {
1307
				$sql = "INSERT INTO ".MAIN_DB_PREFIX."user (datec,login,ldap_sid,entity)";
1308
				$sql .= " VALUES('".$this->db->idate($this->datec)."','".$this->db->escape($this->login)."','".$this->db->escape($this->ldap_sid)."',".$this->db->escape($this->entity).")";
1309
				$result = $this->db->query($sql);
1310
1311
				dol_syslog(get_class($this)."::create", LOG_DEBUG);
1312
				if ($result) {
1313
					$this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."user");
1314
1315
					// Set default rights
1316
					if ($this->set_default_rights() < 0) {
1317
						$this->error = 'ErrorFailedToSetDefaultRightOfUser';
1318
						$this->db->rollback();
1319
						return -5;
1320
					}
1321
1322
					if (!empty($conf->global->MAIN_DEFAULT_WAREHOUSE_USER) && !empty($conf->global->STOCK_USERSTOCK_AUTOCREATE)) {
1323
						require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
1324
						$langs->load("stocks");
1325
						$entrepot = new Entrepot($this->db);
1326
						$entrepot->label = $langs->trans("PersonalStock", $this->getFullName($langs));
1327
						$entrepot->libelle = $entrepot->label; // For backward compatibility
1328
						$entrepot->description = $langs->trans("ThisWarehouseIsPersonalStock", $this->getFullName($langs));
1329
						$entrepot->statut = 1;
1330
						$entrepot->country_id = $mysoc->country_id;
1331
						$warehouseid = $entrepot->create($user);
1332
1333
						$this->fk_warehouse = $warehouseid;
1334
					}
1335
1336
					// Update minor fields
1337
					$result = $this->update($user, 1, 1);
1338
					if ($result < 0) {
1339
						$this->db->rollback();
1340
						return -4;
1341
					}
1342
1343
					if (!$notrigger) {
1344
						// Call trigger
1345
						$result = $this->call_trigger('USER_CREATE', $user);
1346
						if ($result < 0) {
1347
							$error++;
1348
						}
1349
						// End call triggers
1350
					}
1351
1352
					if (!$error) {
1353
						$this->db->commit();
1354
						return $this->id;
1355
					} else {
1356
						//$this->error=$interface->error;
1357
						dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
1358
						$this->db->rollback();
1359
						return -3;
1360
					}
1361
				} else {
1362
					$this->error = $this->db->lasterror();
1363
					$this->db->rollback();
1364
					return -2;
1365
				}
1366
			}
1367
		} else {
1368
			$this->error = $this->db->lasterror();
1369
			$this->db->rollback();
1370
			return -1;
1371
		}
1372
	}
1373
1374
1375
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1376
	/**
1377
	 *  Create a user from a contact object. User will be internal but if contact is linked to a third party, user will be external
1378
	 *
1379
	 *  @param	Contact	$contact    Object for source contact
1380
	 * 	@param  string	$login      Login to force
1381
	 *  @param  string	$password   Password to force
1382
	 *  @return int 				<0 if error, if OK returns id of created user
1383
	 */
1384
	public function create_from_contact($contact, $login = '', $password = '')
1385
	{
1386
		// phpcs:enable
1387
		global $conf, $user, $langs;
1388
1389
		$error = 0;
1390
1391
		// Define parameters
1392
		$this->admin = 0;
1393
		$this->civility_code = $contact->civility_code;
1394
		$this->lastname = $contact->lastname;
1395
		$this->firstname = $contact->firstname;
1396
		$this->gender = $contact->gender;
1397
		$this->email = $contact->email;
1398
		$this->socialnetworks = $contact->socialnetworks;
1399
		$this->office_phone = $contact->phone_pro;
1400
		$this->office_fax = $contact->fax;
1401
		$this->user_mobile = $contact->phone_mobile;
1402
		$this->address = $contact->address;
1403
		$this->zip = $contact->zip;
1404
		$this->town = $contact->town;
1405
		$this->state_id = $contact->state_id;
1406
		$this->country_id = $contact->country_id;
1407
		$this->employee = 0;
1408
1409
		if (empty($login)) {
1410
			include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1411
			$login = dol_buildlogin($contact->lastname, $contact->firstname);
1412
		}
1413
		$this->login = $login;
1414
1415
		$this->db->begin();
1416
1417
		// Create user and set $this->id. Trigger is disabled because executed later.
1418
		$result = $this->create($user, 1);
1419
		if ($result > 0) {
1420
			$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1421
			$sql .= " SET fk_socpeople=".$contact->id;
1422
			$sql .= ", civility=".$contact->civility_code;
1423
			if ($contact->socid) {
1424
				$sql .= ", fk_soc=".$contact->socid;
1425
			}
1426
			$sql .= " WHERE rowid=".$this->id;
1427
			$resql = $this->db->query($sql);
1428
1429
			dol_syslog(get_class($this)."::create_from_contact", LOG_DEBUG);
1430
			if ($resql) {
1431
				$this->context['createfromcontact'] = 'createfromcontact';
1432
1433
				// Call trigger
1434
				$result = $this->call_trigger('USER_CREATE', $user);
1435
				if ($result < 0) {
1436
					$error++; $this->db->rollback(); return -1;
1437
				}
1438
				// End call triggers
1439
1440
				$this->db->commit();
1441
				return $this->id;
1442
			} else {
1443
				$this->error = $this->db->error();
1444
1445
				$this->db->rollback();
1446
				return -1;
1447
			}
1448
		} else {
1449
			// $this->error deja positionne
1450
			dol_syslog(get_class($this)."::create_from_contact - 0");
1451
1452
			$this->db->rollback();
1453
			return $result;
1454
		}
1455
	}
1456
1457
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1458
	/**
1459
	 *  Create a user into database from a member object.
1460
	 *  If $member->fk_soc is set, it will be an external user.
1461
	 *
1462
	 *  @param	Adherent		$member		Object member source
1463
	 * 	@param	string			$login		Login to force
1464
	 *  @return int							<0 if KO, if OK, return id of created account
1465
	 */
1466
	public function create_from_member($member, $login = '')
1467
	{
1468
		// phpcs:enable
1469
		global $conf, $user, $langs;
1470
1471
		// Set properties on new user
1472
		$this->admin = 0;
1473
		$this->civility_code = $member->civility_id;
1474
		$this->lastname     = $member->lastname;
1475
		$this->firstname    = $member->firstname;
1476
		$this->gender = $member->gender;
1477
		$this->email        = $member->email;
1478
		$this->fk_member    = $member->id;
1479
		$this->address      = $member->address;
1480
		$this->zip          = $member->zip;
1481
		$this->town         = $member->town;
1482
		$this->state_id     = $member->state_id;
1483
		$this->country_id   = $member->country_id;
1484
		$this->socialnetworks = $member->socialnetworks;
1485
1486
		$this->pass         = $member->pass;
1487
		$this->pass_crypted = $member->pass_indatabase_crypted;
1488
1489
		if (empty($login)) {
1490
			include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1491
			$login = dol_buildlogin($member->lastname, $member->firstname);
1492
		}
1493
		$this->login = $login;
1494
1495
		$this->db->begin();
1496
1497
		// Create and set $this->id
1498
		$result = $this->create($user);
1499
		if ($result > 0) {
1500
			if (!empty($this->pass)) {	// If a clear password was received (this situation should not happen anymore now), we use it to save it into database
1501
				$newpass = $this->setPassword($user, $this->pass);
1502
				if (is_numeric($newpass) && $newpass < 0) {
1503
					$result = -2;
1504
				}
1505
			} elseif (!empty($this->pass_crypted)) {	// If a crypted password is already known, we save it directly into database because the previous create did not save it.
1506
				$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1507
				$sql .= " SET pass_crypted = '".$this->db->escape($this->pass_crypted)."'";
1508
				$sql .= " WHERE rowid=".$this->id;
1509
1510
				$resql = $this->db->query($sql);
1511
				if (!$resql) {
1512
					$result = -1;
1513
				}
1514
			}
1515
1516
			if ($result > 0 && $member->fk_soc) {	// If member is linked to a thirdparty
1517
				$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1518
				$sql .= " SET fk_soc=".$member->fk_soc;
1519
				$sql .= " WHERE rowid=".$this->id;
1520
1521
				dol_syslog(get_class($this)."::create_from_member", LOG_DEBUG);
1522
				$resql = $this->db->query($sql);
1523
				if ($resql) {
1524
					$this->db->commit();
1525
					return $this->id;
1526
				} else {
1527
					$this->error = $this->db->lasterror();
1528
1529
					$this->db->rollback();
1530
					return -1;
1531
				}
1532
			}
1533
		}
1534
1535
		if ($result > 0) {
1536
			$this->db->commit();
1537
			return $this->id;
1538
		} else {
1539
			// $this->error deja positionne
1540
			$this->db->rollback();
1541
			return -2;
1542
		}
1543
	}
1544
1545
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1546
	/**
1547
	 *    Assign rights by default
1548
	 *
1549
	 *    @return     integer erreur <0, si ok renvoi le nbre de droits par defaut positionnes
1550
	 */
1551
	public function set_default_rights()
1552
	{
1553
		// phpcs:enable
1554
		global $conf;
1555
1556
		$rd = array();
1557
		$num = 0;
1558
		$sql = "SELECT id FROM ".MAIN_DB_PREFIX."rights_def";
1559
		$sql .= " WHERE bydefault = 1";
1560
		$sql .= " AND entity = ".$conf->entity;
1561
1562
		$resql = $this->db->query($sql);
1563
		if ($resql) {
1564
			$num = $this->db->num_rows($resql);
1565
			$i = 0;
1566
			while ($i < $num) {
1567
				$row = $this->db->fetch_row($resql);
1568
				$rd[$i] = $row[0];
1569
				$i++;
1570
			}
1571
			$this->db->free($resql);
1572
		}
1573
		$i = 0;
1574
		while ($i < $num) {
1575
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_rights WHERE fk_user = $this->id AND fk_id=$rd[$i]";
1576
			$result = $this->db->query($sql);
1577
1578
			$sql = "INSERT INTO ".MAIN_DB_PREFIX."user_rights (fk_user, fk_id) VALUES ($this->id, $rd[$i])";
1579
			$result = $this->db->query($sql);
1580
			if (!$result) {
1581
				return -1;
1582
			}
1583
			$i++;
1584
		}
1585
1586
		return $i;
1587
	}
1588
1589
	/**
1590
	 *  	Update a user into database (and also password if this->pass is defined)
1591
	 *
1592
	 *		@param	User	$user				User qui fait la mise a jour
1593
	 *    	@param  int		$notrigger			1 ne declenche pas les triggers, 0 sinon
1594
	 *		@param	int		$nosyncmember		0=Synchronize linked member (standard info), 1=Do not synchronize linked member
1595
	 *		@param	int		$nosyncmemberpass	0=Synchronize linked member (password), 1=Do not synchronize linked member
1596
	 *		@param	int		$nosynccontact		0=Synchronize linked contact, 1=Do not synchronize linked contact
1597
	 *    	@return int 		        		<0 si KO, >=0 si OK
1598
	 */
1599
	public function update($user, $notrigger = 0, $nosyncmember = 0, $nosyncmemberpass = 0, $nosynccontact = 0)
1600
	{
1601
		global $conf, $langs;
1602
1603
		$nbrowsaffected = 0;
1604
		$error = 0;
1605
1606
		dol_syslog(get_class($this)."::update notrigger=".$notrigger.", nosyncmember=".$nosyncmember.", nosyncmemberpass=".$nosyncmemberpass);
1607
1608
		// Clean parameters
1609
		$this->civility_code = trim($this->civility_code);
1610
		$this->lastname     = trim($this->lastname);
1611
		$this->firstname    = trim($this->firstname);
1612
		$this->employee    	= $this->employee ? $this->employee : 0;
1613
		$this->login        = trim($this->login);
1614
		$this->gender       = trim($this->gender);
1615
		$this->pass         = trim($this->pass);
1616
		$this->api_key      = trim($this->api_key);
1617
		$this->address = $this->address ? trim($this->address) : trim($this->address);
1618
		$this->zip = $this->zip ? trim($this->zip) : trim($this->zip);
1619
		$this->town = $this->town ? trim($this->town) : trim($this->town);
1620
		$this->setUpperOrLowerCase();
1621
		$this->state_id = trim($this->state_id);
1622
		$this->country_id = ($this->country_id > 0) ? $this->country_id : 0;
1623
		$this->office_phone = trim($this->office_phone);
1624
		$this->office_fax   = trim($this->office_fax);
1625
		$this->user_mobile  = trim($this->user_mobile);
1626
		$this->personal_mobile = trim($this->personal_mobile);
1627
		$this->email        = trim($this->email);
1628
		$this->personal_email = trim($this->personal_email);
1629
1630
		$this->job = trim($this->job);
1631
		$this->signature    = trim($this->signature);
1632
		$this->note_public  = trim($this->note_public);
1633
		$this->note_private = trim($this->note_private);
1634
		$this->openid       = trim(empty($this->openid) ? '' : $this->openid); // Avoid warning
1635
		$this->admin        = $this->admin ? $this->admin : 0;
1636
		$this->address = empty($this->address) ? '' : $this->address;
1637
		$this->zip			= empty($this->zip) ? '' : $this->zip;
1638
		$this->town = empty($this->town) ? '' : $this->town;
1639
		$this->accountancy_code = trim($this->accountancy_code);
1640
		$this->color = empty($this->color) ? '' : $this->color;
1641
		$this->dateemployment = empty($this->dateemployment) ? '' : $this->dateemployment;
1642
		$this->dateemploymentend = empty($this->dateemploymentend) ? '' : $this->dateemploymentend;
1643
		$this->datestartvalidity = empty($this->datestartvalidity) ? '' : $this->datestartvalidity;
1644
		$this->dateendvalidity = empty($this->dateendvalidity) ? '' : $this->dateendvalidity;
1645
		$this->birth        = trim($this->birth);
1646
		$this->fk_warehouse = (int) $this->fk_warehouse;
1647
1648
		// Check parameters
1649
		if (!empty($conf->global->USER_MAIL_REQUIRED) && !isValidEMail($this->email)) {
1650
			$langs->load("errors");
1651
			$this->error = $langs->trans("ErrorBadEMail", $this->email);
1652
			return -1;
1653
		}
1654
		if (empty($this->login)) {
1655
			$langs->load("errors");
1656
			$this->error = $langs->trans("ErrorFieldRequired", 'Login');
1657
			return -1;
1658
		}
1659
1660
		$this->db->begin();
1661
1662
		// Update datas
1663
		$sql = "UPDATE ".MAIN_DB_PREFIX."user SET";
1664
		$sql .= " civility = '".$this->db->escape($this->civility_code)."'";
1665
		$sql .= ", lastname = '".$this->db->escape($this->lastname)."'";
1666
		$sql .= ", firstname = '".$this->db->escape($this->firstname)."'";
1667
		$sql .= ", employee = ".(int) $this->employee;
1668
		$sql .= ", login = '".$this->db->escape($this->login)."'";
1669
		$sql .= ", api_key = ".($this->api_key ? "'".$this->db->escape($this->api_key)."'" : "null");
1670
		$sql .= ", gender = ".($this->gender != -1 ? "'".$this->db->escape($this->gender)."'" : "null"); // 'man' or 'woman'
1671
		$sql .= ", birth=".(strval($this->birth) != '' ? "'".$this->db->idate($this->birth)."'" : 'null');
1672
		if (!empty($user->admin)) {
1673
			$sql .= ", admin = ".(int) $this->admin; // admin flag can be set/unset only by an admin user
1674
		}
1675
		$sql .= ", address = '".$this->db->escape($this->address)."'";
1676
		$sql .= ", zip = '".$this->db->escape($this->zip)."'";
1677
		$sql .= ", town = '".$this->db->escape($this->town)."'";
1678
		$sql .= ", fk_state = ".((!empty($this->state_id) && $this->state_id > 0) ? "'".$this->db->escape($this->state_id)."'" : "null");
1679
		$sql .= ", fk_country = ".((!empty($this->country_id) && $this->country_id > 0) ? "'".$this->db->escape($this->country_id)."'" : "null");
1680
		$sql .= ", office_phone = '".$this->db->escape($this->office_phone)."'";
1681
		$sql .= ", office_fax = '".$this->db->escape($this->office_fax)."'";
1682
		$sql .= ", user_mobile = '".$this->db->escape($this->user_mobile)."'";
1683
		$sql .= ", personal_mobile = '".$this->db->escape($this->personal_mobile)."'";
1684
		$sql .= ", email = '".$this->db->escape($this->email)."'";
1685
		$sql .= ", personal_email = '".$this->db->escape($this->personal_email)."'";
1686
		$sql .= ", socialnetworks = '".$this->db->escape(json_encode($this->socialnetworks))."'";
1687
		$sql .= ", job = '".$this->db->escape($this->job)."'";
1688
		$sql .= ", signature = '".$this->db->escape($this->signature)."'";
1689
		$sql .= ", accountancy_code = '".$this->db->escape($this->accountancy_code)."'";
1690
		$sql .= ", color = '".$this->db->escape($this->color)."'";
1691
		$sql .= ", dateemployment=".(strval($this->dateemployment) != '' ? "'".$this->db->idate($this->dateemployment)."'" : 'null');
1692
		$sql .= ", dateemploymentend=".(strval($this->dateemploymentend) != '' ? "'".$this->db->idate($this->dateemploymentend)."'" : 'null');
1693
		$sql .= ", datestartvalidity=".(strval($this->datestartvalidity) != '' ? "'".$this->db->idate($this->datestartvalidity)."'" : 'null');
1694
		$sql .= ", dateendvalidity=".(strval($this->dateendvalidity) != '' ? "'".$this->db->idate($this->dateendvalidity)."'" : 'null');
1695
		$sql .= ", note = '".$this->db->escape($this->note_private)."'";
1696
		$sql .= ", note_public = '".$this->db->escape($this->note_public)."'";
1697
		$sql .= ", photo = ".($this->photo ? "'".$this->db->escape($this->photo)."'" : "null");
1698
		$sql .= ", openid = ".($this->openid ? "'".$this->db->escape($this->openid)."'" : "null");
1699
		$sql .= ", fk_user = ".($this->fk_user > 0 ? "'".$this->db->escape($this->fk_user)."'" : "null");
1700
		$sql .= ", fk_user_expense_validator = ".($this->fk_user_expense_validator > 0 ? "'".$this->db->escape($this->fk_user_expense_validator)."'" : "null");
1701
		$sql .= ", fk_user_holiday_validator = ".($this->fk_user_holiday_validator > 0 ? "'".$this->db->escape($this->fk_user_holiday_validator)."'" : "null");
1702
		if (isset($this->thm) || $this->thm != '') {
1703
			$sql .= ", thm= ".($this->thm != '' ? "'".$this->db->escape($this->thm)."'" : "null");
1704
		}
1705
		if (isset($this->tjm) || $this->tjm != '') {
1706
			$sql .= ", tjm= ".($this->tjm != '' ? "'".$this->db->escape($this->tjm)."'" : "null");
1707
		}
1708
		if (isset($this->salary) || $this->salary != '') {
1709
			$sql .= ", salary= ".($this->salary != '' ? "'".$this->db->escape($this->salary)."'" : "null");
1710
		}
1711
		if (isset($this->salaryextra) || $this->salaryextra != '') {
1712
			$sql .= ", salaryextra= ".($this->salaryextra != '' ? "'".$this->db->escape($this->salaryextra)."'" : "null");
1713
		}
1714
		$sql .= ", weeklyhours= ".($this->weeklyhours != '' ? "'".$this->db->escape($this->weeklyhours)."'" : "null");
1715
		$sql .= ", entity = '".$this->db->escape($this->entity)."'";
1716
		$sql .= ", default_range = ".($this->default_range > 0 ? $this->default_range : 'null');
1717
		$sql .= ", default_c_exp_tax_cat = ".($this->default_c_exp_tax_cat > 0 ? $this->default_c_exp_tax_cat : 'null');
1718
		$sql .= ", fk_warehouse = ".($this->fk_warehouse > 0 ? $this->fk_warehouse : "null");
1719
		$sql .= ", lang = ".($this->lang ? "'".$this->db->escape($this->lang)."'" : "null");
1720
		$sql .= " WHERE rowid = ".$this->id;
1721
1722
		dol_syslog(get_class($this)."::update", LOG_DEBUG);
1723
		$resql = $this->db->query($sql);
1724
		if ($resql) {
1725
			$nbrowsaffected += $this->db->affected_rows($resql);
1726
1727
			// Update password
1728
			if (!empty($this->pass)) {
1729
				if ($this->pass != $this->pass_indatabase && $this->pass != $this->pass_indatabase_crypted) {
1730
					// Si mot de passe saisi et different de celui en base
1731
					$result = $this->setPassword($user, $this->pass, 0, $notrigger, $nosyncmemberpass);
1732
					if (!$nbrowsaffected) {
1733
						$nbrowsaffected++;
1734
					}
1735
				}
1736
			}
1737
1738
			// If user is linked to a member, remove old link to this member
1739
			if ($this->fk_member > 0) {
1740
				dol_syslog(get_class($this)."::update remove link with member. We will recreate it later", LOG_DEBUG);
1741
				$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = NULL where fk_member = ".$this->fk_member;
1742
				$resql = $this->db->query($sql);
1743
				if (!$resql) {
1744
					$this->error = $this->db->error(); $this->db->rollback(); return -5;
1745
				}
1746
			}
1747
			// Set link to user
1748
			dol_syslog(get_class($this)."::update set link with member", LOG_DEBUG);
1749
			$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member =".($this->fk_member > 0 ? $this->fk_member : 'null')." where rowid = ".$this->id;
1750
			$resql = $this->db->query($sql);
1751
			if (!$resql) {
1752
				$this->error = $this->db->error(); $this->db->rollback(); return -5;
1753
			}
1754
1755
			if ($nbrowsaffected) {	// If something has changed in data
1756
				if ($this->fk_member > 0 && !$nosyncmember) {
1757
					dol_syslog(get_class($this)."::update user is linked with a member. We try to update member too.", LOG_DEBUG);
1758
1759
					require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
1760
1761
					// This user is linked with a member, so we also update member information
1762
					// if this is an update.
1763
					$adh = new Adherent($this->db);
1764
					$result = $adh->fetch($this->fk_member);
1765
1766
					if ($result > 0) {
1767
						$adh->civility_code = $this->civility_code;
1768
						$adh->firstname = $this->firstname;
1769
						$adh->lastname = $this->lastname;
1770
						$adh->login = $this->login;
1771
						$adh->gender = $this->gender;
1772
						$adh->birth = $this->birth;
1773
1774
						$adh->pass = $this->pass;
1775
1776
						//$adh->societe = (empty($adh->societe) && $this->societe_id ? $this->societe_id : $adh->societe);
1777
1778
						$adh->address = $this->address;
1779
						$adh->town = $this->town;
1780
						$adh->zip = $this->zip;
1781
						$adh->state_id = $this->state_id;
1782
						$adh->country_id = $this->country_id;
1783
1784
						$adh->email = $this->email;
1785
1786
						$adh->socialnetworks = $this->socialnetworks;
1787
1788
						$adh->phone = $this->office_phone;
1789
						$adh->phone_mobile = $this->user_mobile;
1790
1791
						$adh->user_id = $this->id;
1792
						$adh->user_login = $this->login;
1793
1794
						$result = $adh->update($user, 0, 1, 0);
1795
						if ($result < 0) {
1796
							$this->error = $adh->error;
1797
							$this->errors = $adh->errors;
1798
							dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
1799
							$error++;
1800
						}
1801
					} elseif ($result < 0) {
1802
						$this->error = $adh->error;
1803
						$this->errors = $adh->errors;
1804
						$error++;
1805
					}
1806
				}
1807
1808
				if ($this->contact_id > 0 && !$nosynccontact) {
1809
					dol_syslog(get_class($this)."::update user is linked with a contact. We try to update contact too.", LOG_DEBUG);
1810
1811
					require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
1812
1813
					// This user is linked with a contact, so we also update contact information if this is an update.
1814
					$tmpobj = new Contact($this->db);
1815
					$result = $tmpobj->fetch($this->contact_id);
1816
1817
					if ($result >= 0) {
1818
						$tmpobj->civility_code = $this->civility_code;
1819
						$tmpobj->firstname = $this->firstname;
1820
						$tmpobj->lastname = $this->lastname;
1821
						$tmpobj->login = $this->login;
1822
						$tmpobj->gender = $this->gender;
1823
						$tmpobj->birth = $this->birth;
1824
1825
						//$tmpobj->pass=$this->pass;
1826
1827
						//$tmpobj->societe=(empty($tmpobj->societe) && $this->societe_id ? $this->societe_id : $tmpobj->societe);
1828
1829
						$tmpobj->email = $this->email;
1830
1831
						$tmpobj->socialnetworks = $this->socialnetworks;
1832
1833
						$tmpobj->phone_pro = $this->office_phone;
1834
						$tmpobj->phone_mobile = $this->user_mobile;
1835
						$tmpobj->fax = $this->office_fax;
1836
1837
						$tmpobj->address = $this->address;
1838
						$tmpobj->town = $this->town;
1839
						$tmpobj->zip = $this->zip;
1840
						$tmpobj->state_id = $this->state_id;
1841
						$tmpobj->country_id = $this->country_id;
1842
1843
						$tmpobj->user_id = $this->id;
1844
						$tmpobj->user_login = $this->login;
1845
1846
						$result = $tmpobj->update($tmpobj->id, $user, 0, 'update', 1);
1847
						if ($result < 0) {
1848
							$this->error = $tmpobj->error;
1849
							$this->errors = $tmpobj->errors;
1850
							dol_syslog(get_class($this)."::update error after calling adh->update to sync it with user: ".$this->error, LOG_ERR);
1851
							$error++;
1852
						}
1853
					} else {
1854
						$this->error = $tmpobj->error;
1855
						$this->errors = $tmpobj->errors;
1856
						$error++;
1857
					}
1858
				}
1859
			}
1860
1861
			$action = 'update';
1862
1863
			// Actions on extra fields
1864
			if (!$error) {
1865
				$result = $this->insertExtraFields();
1866
				if ($result < 0) {
1867
					$error++;
1868
				}
1869
			}
1870
1871
			if (!$error && !$notrigger) {
1872
				// Call trigger
1873
				$result = $this->call_trigger('USER_MODIFY', $user);
1874
				if ($result < 0) {
1875
					$error++;
1876
				}
1877
				// End call triggers
1878
			}
1879
1880
			if (!$error) {
1881
				$this->db->commit();
1882
				return $nbrowsaffected;
1883
			} else {
1884
				dol_syslog(get_class($this)."::update error=".$this->error, LOG_ERR);
1885
				$this->db->rollback();
1886
				return -1;
1887
			}
1888
		} else {
1889
			$this->error = $this->db->lasterror();
1890
			$this->db->rollback();
1891
			return -2;
1892
		}
1893
	}
1894
1895
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1896
	/**
1897
	 *  Mise a jour en base de la date de derniere connexion d'un utilisateur
1898
	 *  Fonction appelee lors d'une nouvelle connexion
1899
	 *
1900
	 *  @return int     <0 si echec, >=0 si ok
1901
	 */
1902
	public function update_last_login_date()
1903
	{
1904
		// phpcs:enable
1905
		$now = dol_now();
1906
1907
		$sql = "UPDATE ".MAIN_DB_PREFIX."user SET";
1908
		$sql .= " datepreviouslogin = datelastlogin,";
1909
		$sql .= " datelastlogin = '".$this->db->idate($now)."',";
1910
		$sql .= " tms = tms"; // La date de derniere modif doit changer sauf pour la mise a jour de date de derniere connexion
1911
		$sql .= " WHERE rowid = ".$this->id;
1912
1913
		dol_syslog(get_class($this)."::update_last_login_date user->id=".$this->id." ".$sql, LOG_DEBUG);
1914
		$resql = $this->db->query($sql);
1915
		if ($resql) {
1916
			$this->datepreviouslogin = $this->datelastlogin;
1917
			$this->datelastlogin = $now;
1918
			return 1;
1919
		} else {
1920
			$this->error = $this->db->lasterror().' sql='.$sql;
1921
			return -1;
1922
		}
1923
	}
1924
1925
1926
	/**
1927
	 *  Change password of a user
1928
	 *
1929
	 *  @param	User	$user             		Object user of user requesting the change (not the user for who we change the password). May be unknown.
1930
	 *  @param  string	$password         		New password in clear text (to generate if not provided)
1931
	 *	@param	int		$changelater			1=Change password only after clicking on confirm email
1932
	 *	@param	int		$notrigger				1=Does not launch triggers
1933
	 *	@param	int		$nosyncmember	        Do not synchronize linked member
1934
	 *  @return string 			          		If OK return clear password, 0 if no change, < 0 if error
1935
	 */
1936
	public function setPassword($user, $password = '', $changelater = 0, $notrigger = 0, $nosyncmember = 0)
1937
	{
1938
		global $conf, $langs;
1939
		require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1940
1941
		$error = 0;
1942
1943
		dol_syslog(get_class($this)."::setPassword user=".$user->id." password=".preg_replace('/./i', '*', $password)." changelater=".$changelater." notrigger=".$notrigger." nosyncmember=".$nosyncmember, LOG_DEBUG);
1944
1945
		// If new password not provided, we generate one
1946
		if (!$password) {
1947
			$password = getRandomPassword(false);
1948
		}
1949
1950
		// Crypt password
1951
		$password_crypted = dol_hash($password);
1952
1953
		// Mise a jour
1954
		if (!$changelater) {
1955
			if (!is_object($this->oldcopy)) {
1956
				$this->oldcopy = clone $this;
1957
			}
1958
1959
			$this->db->begin();
1960
1961
			$sql = "UPDATE ".MAIN_DB_PREFIX."user";
1962
			$sql .= " SET pass_crypted = '".$this->db->escape($password_crypted)."',";
1963
			$sql .= " pass_temp = null";
1964
			if (!empty($conf->global->DATABASE_PWD_ENCRYPTED)) {
1965
				$sql .= ", pass = null";
1966
			} else {
1967
				$sql .= ", pass = '".$this->db->escape($password)."'";
1968
			}
1969
			$sql .= " WHERE rowid = ".$this->id;
1970
1971
			dol_syslog(get_class($this)."::setPassword", LOG_DEBUG);
1972
			$result = $this->db->query($sql);
1973
			if ($result) {
1974
				if ($this->db->affected_rows($result)) {
1975
					$this->pass = $password;
1976
					$this->pass_indatabase = $password;
1977
					$this->pass_indatabase_crypted = $password_crypted;
1978
1979
					if ($this->fk_member && !$nosyncmember) {
1980
						require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
1981
1982
						// This user is linked with a member, so we also update members informations
1983
						// if this is an update.
1984
						$adh = new Adherent($this->db);
1985
						$result = $adh->fetch($this->fk_member);
1986
1987
						if ($result >= 0) {
1988
							$result = $adh->setPassword($user, $this->pass, (empty($conf->global->DATABASE_PWD_ENCRYPTED) ? 0 : 1), 1); // Cryptage non gere dans module adherent
1989
							if ($result < 0) {
1990
								$this->error = $adh->error;
1991
								dol_syslog(get_class($this)."::setPassword ".$this->error, LOG_ERR);
1992
								$error++;
1993
							}
1994
						} else {
1995
							$this->error = $adh->error;
1996
							$error++;
1997
						}
1998
					}
1999
2000
					dol_syslog(get_class($this)."::setPassword notrigger=".$notrigger." error=".$error, LOG_DEBUG);
2001
2002
					if (!$error && !$notrigger) {
2003
						// Call trigger
2004
						$result = $this->call_trigger('USER_NEW_PASSWORD', $user);
2005
						if ($result < 0) {
2006
							$error++; $this->db->rollback(); return -1;
2007
						}
2008
						// End call triggers
2009
					}
2010
2011
					$this->db->commit();
2012
					return $this->pass;
2013
				} else {
2014
					$this->db->rollback();
2015
					return 0;
2016
				}
2017
			} else {
2018
				$this->db->rollback();
2019
				dol_print_error($this->db);
2020
				return -1;
2021
			}
2022
		} else {
2023
			// We store clear password in password temporary field.
2024
			// After receiving confirmation link, we will crypt it and store it in pass_crypted
2025
			$sql = "UPDATE ".MAIN_DB_PREFIX."user";
2026
			$sql .= " SET pass_temp = '".$this->db->escape($password)."'";
2027
			$sql .= " WHERE rowid = ".$this->id;
2028
2029
			dol_syslog(get_class($this)."::setPassword", LOG_DEBUG); // No log
2030
			$result = $this->db->query($sql);
2031
			if ($result) {
2032
				return $password;
2033
			} else {
2034
				dol_print_error($this->db);
2035
				return -3;
2036
			}
2037
		}
2038
	}
2039
2040
2041
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2042
	/**
2043
	 *  Send new password by email
2044
	 *
2045
	 *  @param	User	$user           Object user that send the email (not the user we send too)
2046
	 *  @param	string	$password       New password
2047
	 *	@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
2048
	 *  @return int 		            < 0 si erreur, > 0 si ok
2049
	 */
2050
	public function send_password($user, $password = '', $changelater = 0)
2051
	{
2052
		// phpcs:enable
2053
		global $conf, $langs;
2054
		global $dolibarr_main_url_root;
2055
2056
		require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2057
2058
		$msgishtml = 0;
2059
2060
		// Define $msg
2061
		$mesg = '';
2062
2063
		$outputlangs = new Translate("", $conf);
2064
2065
		if (isset($this->conf->MAIN_LANG_DEFAULT)
2066
		&& $this->conf->MAIN_LANG_DEFAULT != 'auto') {	// If user has defined its own language (rare because in most cases, auto is used)
2067
			$outputlangs->getDefaultLang($this->conf->MAIN_LANG_DEFAULT);
2068
		}
2069
2070
		if ($this->conf->MAIN_LANG_DEFAULT) {
2071
			$outputlangs->setDefaultLang($this->conf->MAIN_LANG_DEFAULT);
2072
		} else {	// If user has not defined its own language, we used current language
2073
			$outputlangs = $langs;
2074
		}
2075
2076
		// Load translation files required by the page
2077
		$outputlangs->loadLangs(array("main", "errors", "users", "other"));
2078
2079
		$appli = constant('DOL_APPLICATION_TITLE');
2080
		if (!empty($conf->global->MAIN_APPLICATION_TITLE)) {
2081
			$appli = $conf->global->MAIN_APPLICATION_TITLE;
2082
		}
2083
2084
		$subject = $outputlangs->transnoentitiesnoconv("SubjectNewPassword", $appli);
2085
2086
		// Define $urlwithroot
2087
		$urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
2088
		$urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
2089
2090
		if (!$changelater) {
2091
			$url = $urlwithroot.'/';
2092
			$mesg .= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived").".\n";
2093
			$mesg .= $outputlangs->transnoentitiesnoconv("NewKeyIs")." :\n\n";
2094
			$mesg .= $outputlangs->transnoentitiesnoconv("Login")." = ".$this->login."\n";
2095
			$mesg .= $outputlangs->transnoentitiesnoconv("Password")." = ".$password."\n\n";
2096
			$mesg .= "\n";
2097
2098
			$mesg .= $outputlangs->transnoentitiesnoconv("ClickHereToGoTo", $appli).': '.$url."\n\n";
2099
			$mesg .= "--\n";
2100
			$mesg .= $user->getFullName($outputlangs); // Username that send the email (not the user for who we want to reset password)
2101
2102
			dol_syslog(get_class($this)."::send_password changelater is off, url=".$url);
2103
		} else {
2104
			$url = $urlwithroot.'/user/passwordforgotten.php?action=validatenewpassword&username='.urlencode($this->login)."&passwordhash=".dol_hash($password);
2105
2106
			$mesg .= $outputlangs->transnoentitiesnoconv("RequestToResetPasswordReceived")."\n";
2107
			$mesg .= $outputlangs->transnoentitiesnoconv("NewKeyWillBe")." :\n\n";
2108
			$mesg .= $outputlangs->transnoentitiesnoconv("Login")." = ".$this->login."\n";
2109
			$mesg .= $outputlangs->transnoentitiesnoconv("Password")." = ".$password."\n\n";
2110
			$mesg .= "\n";
2111
			$mesg .= $outputlangs->transnoentitiesnoconv("YouMustClickToChange")." :\n";
2112
			$mesg .= $url."\n\n";
2113
			$mesg .= $outputlangs->transnoentitiesnoconv("ForgetIfNothing")."\n\n";
2114
2115
			dol_syslog(get_class($this)."::send_password changelater is on, url=".$url);
2116
		}
2117
2118
		$trackid = 'use'.$this->id;
2119
2120
		$mailfile = new CMailFile(
2121
			$subject,
2122
			$this->email,
2123
			$conf->global->MAIN_MAIL_EMAIL_FROM,
2124
			$mesg,
2125
			array(),
2126
			array(),
2127
			array(),
2128
			'',
2129
			'',
2130
			0,
2131
			$msgishtml,
2132
			'',
2133
			'',
2134
			$trackid
2135
		);
2136
2137
		if ($mailfile->sendfile()) {
2138
			return 1;
2139
		} else {
2140
			$langs->trans("errors");
2141
			$this->error = $langs->trans("ErrorFailedToSendPassword").' '.$mailfile->error;
2142
			return -1;
2143
		}
2144
	}
2145
2146
	/**
2147
	 * 		Renvoie la derniere erreur fonctionnelle de manipulation de l'objet
2148
	 *
2149
	 * 		@return    string      chaine erreur
2150
	 */
2151
	public function error()
2152
	{
2153
		return $this->error;
2154
	}
2155
2156
2157
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2158
	/**
2159
	 *  Read clicktodial information for user
2160
	 *
2161
	 *  @return int <0 if KO, >0 if OK
2162
	 */
2163
	public function fetch_clicktodial()
2164
	{
2165
		// phpcs:enable
2166
		$sql = "SELECT url, login, pass, poste ";
2167
		$sql .= " FROM ".MAIN_DB_PREFIX."user_clicktodial as u";
2168
		$sql .= " WHERE u.fk_user = ".$this->id;
2169
2170
		$resql = $this->db->query($sql);
2171
		if ($resql) {
2172
			if ($this->db->num_rows($resql)) {
2173
				$obj = $this->db->fetch_object($resql);
2174
2175
				$this->clicktodial_url = $obj->url;
2176
				$this->clicktodial_login = $obj->login;
2177
				$this->clicktodial_password = $obj->pass;
2178
				$this->clicktodial_poste = $obj->poste;
2179
			}
2180
2181
			$this->clicktodial_loaded = 1; // Data loaded (found or not)
2182
2183
			$this->db->free($resql);
2184
			return 1;
2185
		} else {
2186
			$this->error = $this->db->error();
2187
			return -1;
2188
		}
2189
	}
2190
2191
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2192
	/**
2193
	 *  Update clicktodial info
2194
	 *
2195
	 *  @return	int  <0 if KO, >0 if OK
2196
	 */
2197
	public function update_clicktodial()
2198
	{
2199
		// phpcs:enable
2200
		$this->db->begin();
2201
2202
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_clicktodial";
2203
		$sql .= " WHERE fk_user = ".$this->id;
2204
2205
		dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2206
		$result = $this->db->query($sql);
2207
2208
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."user_clicktodial";
2209
		$sql .= " (fk_user,url,login,pass,poste)";
2210
		$sql .= " VALUES (".$this->id;
2211
		$sql .= ", '".$this->db->escape($this->clicktodial_url)."'";
2212
		$sql .= ", '".$this->db->escape($this->clicktodial_login)."'";
2213
		$sql .= ", '".$this->db->escape($this->clicktodial_password)."'";
2214
		$sql .= ", '".$this->db->escape($this->clicktodial_poste)."')";
2215
2216
		dol_syslog(get_class($this).'::update_clicktodial', LOG_DEBUG);
2217
		$result = $this->db->query($sql);
2218
		if ($result) {
2219
			$this->db->commit();
2220
			return 1;
2221
		} else {
2222
			$this->db->rollback();
2223
			$this->error = $this->db->lasterror();
2224
			return -1;
2225
		}
2226
	}
2227
2228
2229
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2230
	/**
2231
	 *  Add user into a group
2232
	 *
2233
	 *  @param	int	$group      Id of group
2234
	 *  @param  int		$entity     Entity
2235
	 *  @param  int		$notrigger  Disable triggers
2236
	 *  @return int  				<0 if KO, >0 if OK
2237
	 */
2238
	public function SetInGroup($group, $entity, $notrigger = 0)
2239
	{
2240
		// phpcs:enable
2241
		global $conf, $langs, $user;
2242
2243
		$error = 0;
2244
2245
		$this->db->begin();
2246
2247
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."usergroup_user";
2248
		$sql .= " WHERE fk_user  = ".$this->id;
2249
		$sql .= " AND fk_usergroup = ".$group;
2250
		$sql .= " AND entity = ".$entity;
2251
2252
		$result = $this->db->query($sql);
2253
2254
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."usergroup_user (entity, fk_user, fk_usergroup)";
2255
		$sql .= " VALUES (".$entity.",".$this->id.",".$group.")";
2256
2257
		$result = $this->db->query($sql);
2258
		if ($result) {
2259
			if (!$error && !$notrigger) {
2260
				$this->newgroupid = $group; // deprecated. Remove this.
2261
				$this->context = array('audit'=>$langs->trans("UserSetInGroup"), 'newgroupid'=>$group);
2262
2263
				// Call trigger
2264
				$result = $this->call_trigger('USER_MODIFY', $user);
2265
				if ($result < 0) {
2266
					$error++;
2267
				}
2268
				// End call triggers
2269
			}
2270
2271
			if (!$error) {
2272
				$this->db->commit();
2273
				return 1;
2274
			} else {
2275
				dol_syslog(get_class($this)."::SetInGroup ".$this->error, LOG_ERR);
2276
				$this->db->rollback();
2277
				return -2;
2278
			}
2279
		} else {
2280
			$this->error = $this->db->lasterror();
2281
			$this->db->rollback();
2282
			return -1;
2283
		}
2284
	}
2285
2286
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2287
	/**
2288
	 *  Remove a user from a group
2289
	 *
2290
	 *  @param	int   $group       Id of group
2291
	 *  @param  int		$entity      Entity
2292
	 *  @param  int		$notrigger   Disable triggers
2293
	 *  @return int  			     <0 if KO, >0 if OK
2294
	 */
2295
	public function RemoveFromGroup($group, $entity, $notrigger = 0)
2296
	{
2297
		// phpcs:enable
2298
		global $conf, $langs, $user;
2299
2300
		$error = 0;
2301
2302
		$this->db->begin();
2303
2304
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."usergroup_user";
2305
		$sql .= " WHERE fk_user  = ".$this->id;
2306
		$sql .= " AND fk_usergroup = ".$group;
2307
		$sql .= " AND entity = ".$entity;
2308
2309
		$result = $this->db->query($sql);
2310
		if ($result) {
2311
			if (!$error && !$notrigger) {
2312
				$this->oldgroupid = $group; // deprecated. Remove this.
2313
				$this->context = array('audit'=>$langs->trans("UserRemovedFromGroup"), 'oldgroupid'=>$group);
2314
2315
				// Call trigger
2316
				$result = $this->call_trigger('USER_MODIFY', $user);
2317
				if ($result < 0) {
2318
					$error++;
2319
				}
2320
				// End call triggers
2321
			}
2322
2323
			if (!$error) {
2324
				$this->db->commit();
2325
				return 1;
2326
			} else {
2327
				dol_syslog(get_class($this)."::RemoveFromGroup ".$this->error, LOG_ERR);
2328
				$this->db->rollback();
2329
				return -2;
2330
			}
2331
		} else {
2332
			$this->error = $this->db->lasterror();
2333
			$this->db->rollback();
2334
			return -1;
2335
		}
2336
	}
2337
2338
2339
	/**
2340
	 *  Return a link with photo
2341
	 * 	Use this->id,this->photo
2342
	 *
2343
	 *	@param	int		$width			Width of image
2344
	 *	@param	int		$height			Height of image
2345
	 *  @param	string	$cssclass		Force a css class
2346
	 * 	@param	string	$imagesize		'mini', 'small' or '' (original)
2347
	 *	@return	string					String with URL link
2348
	 */
2349
	public function getPhotoUrl($width, $height, $cssclass = '', $imagesize = '')
2350
	{
2351
		$result = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
2352
		$result .= Form::showphoto('userphoto', $this, $width, $height, 0, $cssclass, $imagesize);
2353
		$result .= '</a>';
2354
2355
		return $result;
2356
	}
2357
2358
	/**
2359
	 *  Return a link to the user card (with optionaly the picto)
2360
	 * 	Use this->id,this->lastname, this->firstname
2361
	 *
2362
	 *	@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)
2363
	 *	@param	string	$option						On what the link point to ('leave', 'nolink', )
2364
	 *  @param  integer $infologin      			0=Add default info tooltip, 1=Add complete info tooltip, -1=No info tooltip
2365
	 *  @param	integer	$notooltip					1=Disable tooltip on picto and name
2366
	 *  @param	int		$maxlen						Max length of visible user name
2367
	 *  @param	int		$hidethirdpartylogo			Hide logo of thirdparty if user is external user
2368
	 *  @param  string  $mode               		''=Show firstname and lastname, 'firstname'=Show only firstname, 'firstelselast'=Show firstname or lastname if not defined, 'login'=Show login
2369
	 *  @param  string  $morecss            		Add more css on link
2370
	 *  @param  int     $save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
2371
	 *	@return	string								String with URL
2372
	 */
2373
	public function getNomUrl($withpictoimg = 0, $option = '', $infologin = 0, $notooltip = 0, $maxlen = 24, $hidethirdpartylogo = 0, $mode = '', $morecss = '', $save_lastsearch_value = -1)
2374
	{
2375
		global $langs, $conf, $db, $hookmanager, $user;
2376
		global $dolibarr_main_authentication, $dolibarr_main_demo;
2377
		global $menumanager;
2378
2379
		if (!$user->rights->user->user->lire && $user->id != $this->id) {
2380
			$option = 'nolink';
2381
		}
2382
2383
		if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpictoimg) {
2384
			$withpictoimg = 0;
2385
		}
2386
2387
		$result = ''; $label = '';
2388
		$companylink = '';
2389
2390
		if (!empty($this->photo)) {
2391
			$label .= '<div class="photointooltip">';
2392
			$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
2393
			$label .= '</div><div style="clear: both;"></div>';
2394
		}
2395
2396
		// Info Login
2397
		$label .= '<div class="centpercent">';
2398
		$label .= img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("User").'</u>';
2399
		$label .= ' '.$this->getLibStatut(4);
2400
		$label .= '<br><b>'.$langs->trans('Name').':</b> '.$this->getFullName($langs, '');
2401
		if (!empty($this->login)) {
2402
			$label .= '<br><b>'.$langs->trans('Login').':</b> '.$this->login;
2403
		}
2404
		if (!empty($this->job)) {
2405
			$label .= '<br><b>'.$langs->trans("Job").':</b> '.$this->job;
2406
		}
2407
		$label .= '<br><b>'.$langs->trans("Email").':</b> '.$this->email;
2408
		if (!empty($this->phone)) {
2409
			$label .= '<br><b>'.$langs->trans("Phone").':</b> '.$this->phone;
2410
		}
2411
		if (!empty($this->admin)) {
2412
			$label .= '<br><b>'.$langs->trans("Administrator").'</b>: '.yn($this->admin);
2413
		}
2414
		if (!empty($this->socid)) {	// Add thirdparty for external users
2415
			$thirdpartystatic = new Societe($db);
2416
			$thirdpartystatic->fetch($this->socid);
2417
			if (empty($hidethirdpartylogo)) {
2418
				$companylink = ' '.$thirdpartystatic->getNomUrl(2, (($option == 'nolink') ? 'nolink' : '')); // picto only of company
2419
			}
2420
			$company = ' ('.$langs->trans("Company").': '.$thirdpartystatic->name.')';
2421
		}
2422
		$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...
2423
		$label .= '<br><b>'.$langs->trans("Type").':</b> '.$type;
2424
		$label .= '</div>';
2425
		if ($infologin > 0) {
2426
			$label .= '<br>';
2427
			$label .= '<br><u>'.$langs->trans("Session").'</u>';
2428
			$label .= '<br><b>'.$langs->trans("IPAddress").'</b>: '.$_SERVER["REMOTE_ADDR"];
2429
			if (!empty($conf->global->MAIN_MODULE_MULTICOMPANY)) {
2430
				$label .= '<br><b>'.$langs->trans("ConnectedOnMultiCompany").':</b> '.$conf->entity.' (user entity '.$this->entity.')';
2431
			}
2432
			$label .= '<br><b>'.$langs->trans("AuthenticationMode").':</b> '.$_SESSION["dol_authmode"].(empty($dolibarr_main_demo) ? '' : ' (demo)');
2433
			$label .= '<br><b>'.$langs->trans("ConnectedSince").':</b> '.dol_print_date($this->datelastlogin, "dayhour", 'tzuser');
2434
			$label .= '<br><b>'.$langs->trans("PreviousConnexion").':</b> '.dol_print_date($this->datepreviouslogin, "dayhour", 'tzuser');
2435
			$label .= '<br><b>'.$langs->trans("CurrentTheme").':</b> '.$conf->theme;
2436
			$label .= '<br><b>'.$langs->trans("CurrentMenuManager").':</b> '.$menumanager->name;
2437
			$s = picto_from_langcode($langs->getDefaultLang());
2438
			$label .= '<br><b>'.$langs->trans("CurrentUserLanguage").':</b> '.($s ? $s.' ' : '').$langs->getDefaultLang();
2439
			$label .= '<br><b>'.$langs->trans("Browser").':</b> '.$conf->browser->name.($conf->browser->version ? ' '.$conf->browser->version : '').' ('.$_SERVER['HTTP_USER_AGENT'].')';
2440
			$label .= '<br><b>'.$langs->trans("Layout").':</b> '.$conf->browser->layout;
2441
			$label .= '<br><b>'.$langs->trans("Screen").':</b> '.$_SESSION['dol_screenwidth'].' x '.$_SESSION['dol_screenheight'];
2442
			if ($conf->browser->layout == 'phone') {
2443
				$label .= '<br><b>'.$langs->trans("Phone").':</b> '.$langs->trans("Yes");
2444
			}
2445
			if (!empty($_SESSION["disablemodules"])) {
2446
				$label .= '<br><b>'.$langs->trans("DisabledModules").':</b> <br>'.join(', ', explode(',', $_SESSION["disablemodules"]));
2447
			}
2448
		}
2449
		if ($infologin < 0) {
2450
			$label = '';
2451
		}
2452
2453
		$url = DOL_URL_ROOT.'/user/card.php?id='.$this->id;
2454
		if ($option == 'leave') {
2455
			$url = DOL_URL_ROOT.'/holiday/list.php?id='.$this->id;
2456
		}
2457
2458
		if ($option != 'nolink') {
2459
			// Add param to save lastsearch_values or not
2460
			$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2461
			if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2462
				$add_save_lastsearch_values = 1;
2463
			}
2464
			if ($add_save_lastsearch_values) {
2465
				$url .= '&save_lastsearch_values=1';
2466
			}
2467
		}
2468
2469
		$linkstart = '<a href="'.$url.'"';
2470
		$linkclose = "";
2471
		if (empty($notooltip)) {
2472
			if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2473
				$langs->load("users");
2474
				$label = $langs->trans("ShowUser");
2475
				$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2476
			}
2477
			$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
2478
			$linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
2479
2480
			/*
2481
			 $hookmanager->initHooks(array('userdao'));
2482
			 $parameters=array('id'=>$this->id);
2483
			 $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action);    // Note that $action and $object may have been modified by some hooks
2484
			 if ($reshook > 0) $linkclose = $hookmanager->resPrint;
2485
			 */
2486
		}
2487
2488
		$linkstart .= $linkclose.'>';
2489
		$linkend = '</a>';
2490
2491
		//if ($withpictoimg == -1) $result.='<div class="nowrap">';
2492
		$result .= (($option == 'nolink') ? '' : $linkstart);
2493
		if ($withpictoimg) {
2494
			$paddafterimage = '';
2495
			if (abs($withpictoimg) == 1) {
2496
				$paddafterimage = 'style="margin-'.($langs->trans("DIRECTION") == 'rtl' ? 'left' : 'right').': 3px;"';
2497
			}
2498
			// Only picto
2499
			if ($withpictoimg > 0) {
2500
				$picto = '<!-- picto user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'">'.img_object('', 'user', $paddafterimage.' '.($notooltip ? '' : 'class="paddingright classfortooltip"'), 0, 0, $notooltip ? 0 : 1).'</span>';
2501
			}
2502
			// Picto must be a photo
2503
			else {
2504
				$picto = '<!-- picto photo user --><span class="nopadding userimg'.($morecss ? ' '.$morecss : '').'"'.($paddafterimage ? ' '.$paddafterimage : '').'>'.Form::showphoto('userphoto', $this, 0, 0, 0, 'userphoto'.($withpictoimg == -3 ? 'small' : ''), 'mini', 0, 1).'</span>';
2505
			}
2506
			$result .= $picto;
2507
		}
2508
		if ($withpictoimg > -2 && $withpictoimg != 2) {
2509
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2510
				$result .= '<span class=" nopadding usertext'.((!isset($this->statut) || $this->statut) ? '' : ' strikefordisabled').($morecss ? ' '.$morecss : '').'">';
2511
			}
2512
			if ($mode == 'login') {
2513
				$result .= dol_trunc($this->login, $maxlen);
2514
			} else {
2515
				$result .= $this->getFullName($langs, '', ($mode == 'firstelselast' ? 3 : ($mode == 'firstname' ? 2 : -1)), $maxlen);
2516
			}
2517
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2518
				$result .= '</span>';
2519
			}
2520
		}
2521
		$result .= (($option == 'nolink') ? '' : $linkend);
2522
		//if ($withpictoimg == -1) $result.='</div>';
2523
2524
		$result .= $companylink;
2525
2526
		global $action;
2527
		$hookmanager->initHooks(array('userdao'));
2528
		$parameters = array('id'=>$this->id, 'getnomurl'=>$result);
2529
		$reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks
2530
		if ($reshook > 0) {
2531
			$result = $hookmanager->resPrint;
2532
		} else {
2533
			$result .= $hookmanager->resPrint;
2534
		}
2535
2536
		return $result;
2537
	}
2538
2539
	/**
2540
	 *  Return clickable link of login (eventualy with picto)
2541
	 *
2542
	 *	@param	int		$withpicto		Include picto into link
2543
	 *	@param	string	$option			Sur quoi pointe le lien
2544
	 *	@return	string					Chaine avec URL
2545
	 */
2546
	public function getLoginUrl($withpicto = 0, $option = '')
2547
	{
2548
		global $langs, $user;
2549
2550
		$result = '';
2551
2552
		$linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
2553
		$linkend = '</a>';
2554
2555
		//Check user's rights to see an other user
2556
		if ((!$user->rights->user->user->lire && $this->id != $user->id)) {
2557
			$option = 'nolink';
2558
		}
2559
2560
		if ($option == 'xxx') {
2561
			$linkstart = '<a href="'.DOL_URL_ROOT.'/user/card.php?id='.$this->id.'">';
2562
			$linkend = '</a>';
2563
		}
2564
2565
		if ($option == 'nolink') {
2566
			$linkstart = '';
2567
			$linkend = '';
2568
		}
2569
2570
		$result .= $linkstart;
2571
		if ($withpicto) {
2572
			$result .= img_object($langs->trans("ShowUser"), 'user', 'class="paddingright"');
2573
		}
2574
		$result .= $this->login;
2575
		$result .= $linkend;
2576
		return $result;
2577
	}
2578
2579
	/**
2580
	 *  Return the label of the status of user (active, inactive)
2581
	 *
2582
	 *  @param  int		$mode          0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
2583
	 *  @return	string 			       Label of status
2584
	 */
2585
	public function getLibStatut($mode = 0)
2586
	{
2587
		return $this->LibStatut($this->statut, $mode);
2588
	}
2589
2590
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2591
	/**
2592
	 *  Return the label of a status of user (active, inactive)
2593
	 *
2594
	 *  @param  int     $status         Id status
2595
	 *  @param  int		$mode           0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
2596
	 *  @return string                  Label of status
2597
	 */
2598
	public function LibStatut($status, $mode = 0)
2599
	{
2600
		// phpcs:enable
2601
		global $langs;
2602
2603
		if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
2604
			global $langs;
2605
			//$langs->load("mymodule");
2606
			$this->labelStatus[self::STATUS_ENABLED] = $langs->trans('Enabled');
2607
			$this->labelStatus[self::STATUS_DISABLED] = $langs->trans('Disabled');
2608
			$this->labelStatusShort[self::STATUS_ENABLED] = $langs->trans('Enabled');
2609
			$this->labelStatusShort[self::STATUS_DISABLED] = $langs->trans('Disabled');
2610
		}
2611
2612
		$statusType = 'status5';
2613
		if ($status == self::STATUS_ENABLED) {
2614
			$statusType = 'status4';
2615
		}
2616
2617
		return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
2618
	}
2619
2620
2621
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2622
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2623
	/**
2624
	 *	Retourne chaine DN complete dans l'annuaire LDAP pour l'objet
2625
	 *
2626
	 *	@param	array	$info		Info array loaded by _load_ldap_info
2627
	 *	@param	int		$mode		0=Return full DN (uid=qqq,ou=xxx,dc=aaa,dc=bbb)
2628
	 *								1=Return parent (ou=xxx,dc=aaa,dc=bbb)
2629
	 *								2=Return key only (RDN) (uid=qqq)
2630
	 *	@return	string				DN
2631
	 */
2632
	public function _load_ldap_dn($info, $mode = 0)
2633
	{
2634
		// phpcs:enable
2635
		global $conf;
2636
		$dn = '';
2637
		if ($mode == 0) {
2638
			$dn = $conf->global->LDAP_KEY_USERS."=".$info[$conf->global->LDAP_KEY_USERS].",".$conf->global->LDAP_USER_DN;
2639
		} elseif ($mode == 1) {
2640
			$dn = $conf->global->LDAP_USER_DN;
2641
		} elseif ($mode == 2) {
2642
			$dn = $conf->global->LDAP_KEY_USERS."=".$info[$conf->global->LDAP_KEY_USERS];
2643
		}
2644
		return $dn;
2645
	}
2646
2647
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2648
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2649
	/**
2650
	 *	Initialize the info array (array of LDAP values) that will be used to call LDAP functions
2651
	 *
2652
	 *	@return		array		Tableau info des attributs
2653
	 */
2654
	public function _load_ldap_info()
2655
	{
2656
		// phpcs:enable
2657
		global $conf, $langs;
2658
2659
		$info = array();
2660
2661
		$socialnetworks = getArrayOfSocialNetworks();
2662
2663
		$keymodified = false;
2664
2665
		// Object classes
2666
		$info["objectclass"] = explode(',', $conf->global->LDAP_USER_OBJECT_CLASS);
2667
2668
		$this->fullname = $this->getFullName($langs);
2669
2670
		// Possible LDAP KEY (constname => varname)
2671
		$ldapkey = array(
2672
			'LDAP_FIELD_FULLNAME'	=> 'fullname',
2673
			'LDAP_FIELD_NAME'		=> 'lastname',
2674
			'LDAP_FIELD_FIRSTNAME'	=> 'firstname',
2675
			'LDAP_FIELD_LOGIN'		=> 'login',
2676
			'LDAP_FIELD_LOGIN_SAMBA'=> 'login',
2677
			'LDAP_FIELD_PHONE'		=> 'office_phone',
2678
			'LDAP_FIELD_MOBILE'		=> 'user_mobile',
2679
			'LDAP_FIELD_FAX'		=> 'office_fax',
2680
			'LDAP_FIELD_MAIL'		=> 'email',
2681
			'LDAP_FIELD_SID'		=> 'ldap_sid',
2682
		);
2683
2684
		// Champs
2685
		foreach ($ldapkey as $constname => $varname) {
2686
			if (!empty($this->$varname) && !empty($conf->global->$constname)) {
2687
				$info[$conf->global->$constname] = $this->$varname;
2688
2689
				// Check if it is the LDAP key and if its value has been changed
2690
				if (!empty($conf->global->LDAP_KEY_USERS) && $conf->global->LDAP_KEY_USERS == $conf->global->$constname) {
2691
					if (!empty($this->oldcopy) && $this->$varname != $this->oldcopy->$varname) {
2692
						$keymodified = true; // For check if LDAP key has been modified
2693
					}
2694
				}
2695
			}
2696
		}
2697
		foreach ($socialnetworks as $key => $value) {
2698
			if ($this->socialnetworks[$value['label']] && !empty($conf->global->{'LDAP_FIELD_'.strtoupper($value['label'])})) {
2699
				$info[$conf->global->{'LDAP_FIELD_'.strtoupper($value['label'])}] = $this->socialnetworks[$value['label']];
2700
			}
2701
		}
2702
		if ($this->address && !empty($conf->global->LDAP_FIELD_ADDRESS)) {
2703
			$info[$conf->global->LDAP_FIELD_ADDRESS] = $this->address;
2704
		}
2705
		if ($this->zip && !empty($conf->global->LDAP_FIELD_ZIP)) {
2706
			$info[$conf->global->LDAP_FIELD_ZIP] = $this->zip;
2707
		}
2708
		if ($this->town && !empty($conf->global->LDAP_FIELD_TOWN)) {
2709
			$info[$conf->global->LDAP_FIELD_TOWN] = $this->town;
2710
		}
2711
		if ($this->note_public && !empty($conf->global->LDAP_FIELD_DESCRIPTION)) {
2712
			$info[$conf->global->LDAP_FIELD_DESCRIPTION] = dol_string_nohtmltag($this->note_public, 2);
2713
		}
2714
		if ($this->socid > 0) {
2715
			$soc = new Societe($this->db);
2716
			$soc->fetch($this->socid);
2717
2718
			$info[$conf->global->LDAP_FIELD_COMPANY] = $soc->name;
2719
			if ($soc->client == 1) {
2720
				$info["businessCategory"] = "Customers";
2721
			}
2722
			if ($soc->client == 2) {
2723
				$info["businessCategory"] = "Prospects";
2724
			}
2725
			if ($soc->fournisseur == 1) {
2726
				$info["businessCategory"] = "Suppliers";
2727
			}
2728
		}
2729
2730
		// When password is modified
2731
		if (!empty($this->pass)) {
2732
			if (!empty($conf->global->LDAP_FIELD_PASSWORD)) {
2733
				$info[$conf->global->LDAP_FIELD_PASSWORD] = $this->pass; // this->pass = mot de passe non crypte
2734
			}
2735
			if (!empty($conf->global->LDAP_FIELD_PASSWORD_CRYPTED)) {
2736
				$info[$conf->global->LDAP_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass, 4); // Create OpenLDAP MD5 password (TODO add type of encryption)
2737
			}
2738
		}
2739
		// Set LDAP password if possible
2740
		elseif ($conf->global->LDAP_SERVER_PROTOCOLVERSION !== '3') { // If ldap key is modified and LDAPv3 we use ldap_rename function for avoid lose encrypt password
2741
			if (!empty($conf->global->DATABASE_PWD_ENCRYPTED)) {
2742
				// Just for the default MD5 !
2743
				if (empty($conf->global->MAIN_SECURITY_HASH_ALGO)) {
2744
					if ($this->pass_indatabase_crypted && !empty($conf->global->LDAP_FIELD_PASSWORD_CRYPTED)) {
2745
						$info[$conf->global->LDAP_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass_indatabase_crypted, 5); // Create OpenLDAP MD5 password from Dolibarr MD5 password
2746
					}
2747
				}
2748
			}
2749
			// Use $this->pass_indatabase value if exists
2750
			elseif (!empty($this->pass_indatabase)) {
2751
				if (!empty($conf->global->LDAP_FIELD_PASSWORD)) {
2752
					$info[$conf->global->LDAP_FIELD_PASSWORD] = $this->pass_indatabase; // $this->pass_indatabase = mot de passe non crypte
2753
				}
2754
				if (!empty($conf->global->LDAP_FIELD_PASSWORD_CRYPTED)) {
2755
					$info[$conf->global->LDAP_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass_indatabase, 4); // md5 for OpenLdap TODO add type of encryption
2756
				}
2757
			}
2758
		}
2759
2760
		if ($conf->global->LDAP_SERVER_TYPE == 'egroupware') {
2761
			$info["objectclass"][4] = "phpgwContact"; // compatibilite egroupware
2762
2763
			$info['uidnumber'] = $this->id;
2764
2765
			$info['phpgwTz'] = 0;
2766
			$info['phpgwMailType'] = 'INTERNET';
2767
			$info['phpgwMailHomeType'] = 'INTERNET';
2768
2769
			$info["phpgwContactTypeId"] = 'n';
2770
			$info["phpgwContactCatId"] = 0;
2771
			$info["phpgwContactAccess"] = "public";
2772
2773
			if (dol_strlen($this->egroupware_id) == 0) {
2774
				$this->egroupware_id = 1;
2775
			}
2776
2777
			$info["phpgwContactOwner"] = $this->egroupware_id;
2778
2779
			if ($this->email) {
2780
				$info["rfc822Mailbox"] = $this->email;
2781
			}
2782
			if ($this->phone_mobile) {
2783
				$info["phpgwCellTelephoneNumber"] = $this->phone_mobile;
2784
			}
2785
		}
2786
2787
		if (!empty($conf->global->LDAP_FIELD_USERID)) {
2788
			$info[$conf->global->LDAP_FIELD_USERID] = $this->id;
2789
		}
2790
		if (!empty($info[$conf->global->LDAP_FIELD_GROUPID])) {
2791
			$usergroup = new UserGroup($this->db);
2792
			$groupslist = $usergroup->listGroupsForUser($this->id);
2793
			$info[$conf->global->LDAP_FIELD_GROUPID] = '1';
2794
			if (!empty($groupslist)) {
2795
				foreach ($groupslist as $groupforuser) {
2796
					$info[$conf->global->LDAP_FIELD_GROUPID] = $groupforuser->id; //Select first group in list
2797
					break;
2798
				}
2799
			}
2800
		}
2801
		if (!empty($this->firstname) && !empty($conf->global->LDAP_FIELD_HOMEDIRECTORY) && !empty($conf->global->LDAP_FIELD_HOMEDIRECTORYPREFIX)) {
2802
			$info[$conf->global->LDAP_FIELD_HOMEDIRECTORY] = "{$conf->global->LDAP_FIELD_HOMEDIRECTORYPREFIX}/$this->firstname";
2803
		}
2804
2805
		return $info;
2806
	}
2807
2808
2809
	/**
2810
	 *  Initialise an instance with random values.
2811
	 *  Used to build previews or test instances.
2812
	 *	id must be 0 if object instance is a specimen.
2813
	 *
2814
	 *  @return	int
2815
	 */
2816
	public function initAsSpecimen()
2817
	{
2818
		global $user, $langs;
2819
2820
		$now = dol_now();
2821
2822
		// Initialise parametres
2823
		$this->id = 0;
2824
		$this->ref = 'SPECIMEN';
2825
		$this->specimen = 1;
2826
2827
		$this->lastname = 'DOLIBARR';
2828
		$this->firstname = 'SPECIMEN';
2829
		$this->gender = 'man';
2830
		$this->note_public = 'This is a note public';
2831
		$this->note_private = 'This is a note private';
2832
		$this->email = '[email protected]';
2833
		$this->personal_email = '[email protected]';
2834
		$this->socialnetworks = array(
2835
			'skype' => 'skypepseudo',
2836
			'twitter' => 'twitterpseudo',
2837
			'facebook' => 'facebookpseudo',
2838
			'linkedin' => 'linkedinpseudo',
2839
		);
2840
		$this->office_phone = '0999999999';
2841
		$this->office_fax = '0999999998';
2842
		$this->user_mobile = '0999999997';
2843
		$this->personal_mobile = '0999999996';
2844
		$this->admin = 0;
2845
		$this->login = 'dolibspec';
2846
		$this->pass = 'dolibspec';
2847
		//$this->pass_indatabase='dolibspec';									Set after a fetch
2848
		//$this->pass_indatabase_crypted='e80ca5a88c892b0aaaf7e154853bccab';	Set after a fetch
2849
		$this->datec = $now;
2850
		$this->datem = $now;
2851
2852
		$this->datelastlogin = $now;
2853
		$this->datepreviouslogin = $now;
2854
		$this->statut = 1;
2855
2856
		$this->entity = 1;
2857
		return 1;
2858
	}
2859
2860
	/**
2861
	 *  Load info of user object
2862
	 *
2863
	 *  @param  int		$id     Id of user to load
2864
	 *  @return	void
2865
	 */
2866
	public function info($id)
2867
	{
2868
		$sql = "SELECT u.rowid, u.login as ref, u.datec,";
2869
		$sql .= " u.tms as date_modification, u.entity";
2870
		$sql .= " FROM ".MAIN_DB_PREFIX."user as u";
2871
		$sql .= " WHERE u.rowid = ".$id;
2872
2873
		$result = $this->db->query($sql);
2874
		if ($result) {
2875
			if ($this->db->num_rows($result)) {
2876
				$obj = $this->db->fetch_object($result);
2877
2878
				$this->id = $obj->rowid;
2879
2880
				$this->ref = (!$obj->ref) ? $obj->rowid : $obj->ref;
2881
				$this->date_creation = $this->db->jdate($obj->datec);
2882
				$this->date_modification = $this->db->jdate($obj->date_modification);
2883
				$this->entity = $obj->entity;
2884
			}
2885
2886
			$this->db->free($result);
2887
		} else {
2888
			dol_print_error($this->db);
2889
		}
2890
	}
2891
2892
2893
	/**
2894
	 *    Return number of mass Emailing received by this contacts with its email
2895
	 *
2896
	 *    @return       int     Number of EMailings
2897
	 */
2898
	public function getNbOfEMailings()
2899
	{
2900
		$sql = "SELECT count(mc.email) as nb";
2901
		$sql .= " FROM ".MAIN_DB_PREFIX."mailing_cibles as mc";
2902
		$sql .= " WHERE mc.email = '".$this->db->escape($this->email)."'";
2903
		$sql .= " AND mc.statut NOT IN (-1,0)"; // -1 erreur, 0 non envoye, 1 envoye avec succes
2904
2905
		$resql = $this->db->query($sql);
2906
		if ($resql) {
2907
			$obj = $this->db->fetch_object($resql);
2908
			$nb = $obj->nb;
2909
2910
			$this->db->free($resql);
2911
			return $nb;
2912
		} else {
2913
			$this->error = $this->db->error();
2914
			return -1;
2915
		}
2916
	}
2917
2918
	/**
2919
	 *  Return number of existing users
2920
	 *
2921
	 *  @param	string	$limitTo	Limit to '' or 'active'
2922
	 *  @param	string	$option		'superadmin' = return for entity 0 only
2923
	 *  @param	int		$admin		Filter on admin tag
2924
	 *  @return int  				Number of users
2925
	 */
2926
	public function getNbOfUsers($limitTo, $option = '', $admin = -1)
2927
	{
2928
		global $conf;
2929
2930
		$sql = "SELECT count(rowid) as nb";
2931
		$sql .= " FROM ".MAIN_DB_PREFIX."user";
2932
		if ($option == 'superadmin') {
2933
			$sql .= " WHERE entity = 0";
2934
		} else {
2935
			$sql .= " WHERE entity IN (".getEntity('user', 0).")";
2936
			if ($limitTo == 'active') {
2937
				$sql .= " AND statut = 1";
2938
			}
2939
		}
2940
		if ($admin >= 0) {
2941
			$sql .= " AND admin = ".(int) $admin;
2942
		}
2943
2944
		$resql = $this->db->query($sql);
2945
		if ($resql) {
2946
			$obj = $this->db->fetch_object($resql);
2947
			$nb = (int) $obj->nb;
2948
2949
			$this->db->free($resql);
2950
			return $nb;
2951
		} else {
2952
			$this->error = $this->db->lasterror();
2953
			return -1;
2954
		}
2955
	}
2956
2957
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2958
	/**
2959
	 *  Update user using data from the LDAP
2960
	 *
2961
	 *  @param	Object	$ldapuser	Ladp User
2962
	 *  @return int  				<0 if KO, >0 if OK
2963
	 */
2964
	public function update_ldap2dolibarr(&$ldapuser)
2965
	{
2966
		// phpcs:enable
2967
		// TODO: Voir pourquoi le update met à jour avec toutes les valeurs vide (global $user écrase ?)
2968
		global $user, $conf;
2969
2970
		$socialnetworks = getArrayOfSocialNetworks();
2971
2972
		$this->firstname = $ldapuser->{$conf->global->LDAP_FIELD_FIRSTNAME};
2973
		$this->lastname = $ldapuser->{$conf->global->LDAP_FIELD_NAME};
2974
		$this->login = $ldapuser->{$conf->global->LDAP_FIELD_LOGIN};
2975
		$this->pass = $ldapuser->{$conf->global->LDAP_FIELD_PASSWORD};
2976
		$this->pass_indatabase_crypted = $ldapuser->{$conf->global->LDAP_FIELD_PASSWORD_CRYPTED};
2977
2978
		$this->office_phone = $ldapuser->{$conf->global->LDAP_FIELD_PHONE};
2979
		$this->user_mobile = $ldapuser->{$conf->global->LDAP_FIELD_MOBILE};
2980
		$this->office_fax = $ldapuser->{$conf->global->LDAP_FIELD_FAX};
2981
		$this->email = $ldapuser->{$conf->global->LDAP_FIELD_MAIL};
2982
		foreach ($socialnetworks as $key => $value) {
2983
			$tmpkey = 'LDAP_FIELD_'.strtoupper($value['label']);
2984
			$this->socialnetworks[$value['label']] = $ldapuser->{$conf->global->$tmpkey};
2985
		}
2986
		$this->ldap_sid = $ldapuser->{$conf->global->LDAP_FIELD_SID};
2987
2988
		$this->job = $ldapuser->{$conf->global->LDAP_FIELD_TITLE};
2989
		$this->note_public = $ldapuser->{$conf->global->LDAP_FIELD_DESCRIPTION};
2990
2991
		$result = $this->update($user);
2992
2993
		dol_syslog(get_class($this)."::update_ldap2dolibarr result=".$result, LOG_DEBUG);
2994
2995
		return $result;
2996
	}
2997
2998
2999
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3000
	/**
3001
	 * Return and array with all instanciated first level children users of current user
3002
	 *
3003
	 * @return	User[]|int
3004
	 * @see getAllChildIds()
3005
	 */
3006
	public function get_children()
3007
	{
3008
		// phpcs:enable
3009
		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."user";
3010
		$sql .= " WHERE fk_user = ".$this->id;
3011
3012
		dol_syslog(get_class($this)."::get_children sql=".$sql, LOG_DEBUG);
3013
		$res = $this->db->query($sql);
3014
		if ($res) {
3015
			$users = array();
3016
			while ($rec = $this->db->fetch_array($res)) {
3017
				$user = new User($this->db);
3018
				$user->fetch($rec['rowid']);
3019
				$users[] = $user;
3020
			}
3021
			return $users;
3022
		} else {
3023
			dol_print_error($this->db);
3024
			return -1;
3025
		}
3026
	}
3027
3028
3029
	/**
3030
	 *  Load this->parentof that is array(id_son=>id_parent, ...)
3031
	 *
3032
	 *  @return     int     <0 if KO, >0 if OK
3033
	 */
3034
	private function loadParentOf()
3035
	{
3036
		global $conf;
3037
3038
		$this->parentof = array();
3039
3040
		// Load array[child]=parent
3041
		$sql = "SELECT fk_user as id_parent, rowid as id_son";
3042
		$sql .= " FROM ".MAIN_DB_PREFIX."user";
3043
		$sql .= " WHERE fk_user <> 0";
3044
		$sql .= " AND entity IN (".getEntity('user').")";
3045
3046
		dol_syslog(get_class($this)."::loadParentOf", LOG_DEBUG);
3047
		$resql = $this->db->query($sql);
3048
		if ($resql) {
3049
			while ($obj = $this->db->fetch_object($resql)) {
3050
				$this->parentof[$obj->id_son] = $obj->id_parent;
3051
			}
3052
			return 1;
3053
		} else {
3054
			dol_print_error($this->db);
3055
			return -1;
3056
		}
3057
	}
3058
3059
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3060
	/**
3061
	 * 	Build the hierarchy/tree of users into an array.
3062
	 *	Set and return this->users that is an array sorted according to tree with arrays of:
3063
	 *				id = id user
3064
	 *				lastname
3065
	 *				firstname
3066
	 *				fullname = nom avec chemin complet du user
3067
	 *				fullpath = chemin complet compose des id: "_grandparentid_parentid_id"
3068
	 *
3069
	 *  @param      int		$deleteafterid      Removed all users including the leaf $deleteafterid (and all its child) in user tree.
3070
	 *  @param		string	$filter				SQL filter on users
3071
	 *	@return		array		      		  	Array of users $this->users. Note: $this->parentof is also set.
3072
	 */
3073
	public function get_full_tree($deleteafterid = 0, $filter = '')
3074
	{
3075
		// phpcs:enable
3076
		global $conf, $user;
3077
		global $hookmanager;
3078
3079
		// Actions hooked (by external module)
3080
		$hookmanager->initHooks(array('userdao'));
3081
3082
		$this->users = array();
3083
3084
		// Init this->parentof that is array(id_son=>id_parent, ...)
3085
		$this->loadParentOf();
3086
3087
		// Init $this->users array
3088
		$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
3089
		$sql .= " FROM ".MAIN_DB_PREFIX."user as u";
3090
		// Add fields from hooks
3091
		$parameters = array();
3092
		$reshook = $hookmanager->executeHooks('printUserListWhere', $parameters); // Note that $action and $object may have been modified by hook
3093
		if ($reshook > 0) {
3094
			$sql .= $hookmanager->resPrint;
3095
		} else {
3096
			$sql .= " WHERE u.entity IN (".getEntity('user').")";
3097
		}
3098
		if ($filter) {
3099
			$sql .= " AND ".$filter;
3100
		}
3101
3102
		dol_syslog(get_class($this)."::get_full_tree get user list", LOG_DEBUG);
3103
		$resql = $this->db->query($sql);
3104
		if ($resql) {
3105
			$i = 0;
3106
			while ($obj = $this->db->fetch_object($resql)) {
3107
				$this->users[$obj->rowid]['rowid'] = $obj->rowid;
3108
				$this->users[$obj->rowid]['id'] = $obj->rowid;
3109
				$this->users[$obj->rowid]['fk_user'] = $obj->fk_user;
3110
				$this->users[$obj->rowid]['fk_soc'] = $obj->fk_soc;
3111
				$this->users[$obj->rowid]['firstname'] = $obj->firstname;
3112
				$this->users[$obj->rowid]['lastname'] = $obj->lastname;
3113
				$this->users[$obj->rowid]['login'] = $obj->login;
3114
				$this->users[$obj->rowid]['statut'] = $obj->statut;
3115
				$this->users[$obj->rowid]['entity'] = $obj->entity;
3116
				$this->users[$obj->rowid]['email'] = $obj->email;
3117
				$this->users[$obj->rowid]['gender'] = $obj->gender;
3118
				$this->users[$obj->rowid]['admin'] = $obj->admin;
3119
				$this->users[$obj->rowid]['photo'] = $obj->photo;
3120
				$i++;
3121
			}
3122
		} else {
3123
			dol_print_error($this->db);
3124
			return -1;
3125
		}
3126
3127
		// We add the fullpath property to each elements of first level (no parent exists)
3128
		dol_syslog(get_class($this)."::get_full_tree call to build_path_from_id_user", LOG_DEBUG);
3129
		foreach ($this->users as $key => $val) {
3130
			$result = $this->build_path_from_id_user($key, 0); // Process a branch from the root user key (this user has no parent)
3131
			if ($result < 0) {
3132
				$this->error = 'ErrorLoopInHierarchy';
3133
				return -1;
3134
			}
3135
		}
3136
3137
		// Exclude leaf including $deleteafterid from tree
3138
		if ($deleteafterid) {
3139
			//print "Look to discard user ".$deleteafterid."\n";
3140
			$keyfilter1 = '^'.$deleteafterid.'$';
3141
			$keyfilter2 = '_'.$deleteafterid.'$';
3142
			$keyfilter3 = '^'.$deleteafterid.'_';
3143
			$keyfilter4 = '_'.$deleteafterid.'_';
3144
			foreach ($this->users as $key => $val) {
3145
				if (preg_match('/'.$keyfilter1.'/', $val['fullpath']) || preg_match('/'.$keyfilter2.'/', $val['fullpath'])
3146
					|| preg_match('/'.$keyfilter3.'/', $val['fullpath']) || preg_match('/'.$keyfilter4.'/', $val['fullpath'])) {
3147
					unset($this->users[$key]);
3148
				}
3149
			}
3150
		}
3151
3152
		dol_syslog(get_class($this)."::get_full_tree dol_sort_array", LOG_DEBUG);
3153
		$this->users = dol_sort_array($this->users, 'fullname', 'asc', true, false);
3154
3155
		//var_dump($this->users);
3156
3157
		return $this->users;
3158
	}
3159
3160
	/**
3161
	 * 	Return list of all child users id in herarchy (all sublevels).
3162
	 *  Note: Calling this function also reset full list of users into $this->users.
3163
	 *
3164
	 *  @param      int      $addcurrentuser    1=Add also current user id to the list.
3165
	 *	@return		array		      		  	Array of user id lower than user (all levels under user). This overwrite this->users.
3166
	 *  @see get_children()
3167
	 */
3168
	public function getAllChildIds($addcurrentuser = 0)
3169
	{
3170
		$childids = array();
3171
3172
		if (isset($this->cache_childids[$this->id])) {
3173
			$childids = $this->cache_childids[$this->id];
3174
		} else {
3175
			// Init this->users
3176
			$this->get_full_tree();
3177
3178
			$idtoscan = $this->id;
3179
3180
			dol_syslog("Build childid for id = ".$idtoscan);
3181
			foreach ($this->users as $id => $val) {
3182
				//var_dump($val['fullpath']);
3183
				if (preg_match('/_'.$idtoscan.'_/', $val['fullpath'])) {
3184
					$childids[$val['id']] = $val['id'];
3185
				}
3186
			}
3187
		}
3188
		$this->cache_childids[$this->id] = $childids;
3189
3190
		if ($addcurrentuser) {
3191
			$childids[$this->id] = $this->id;
3192
		}
3193
3194
		return $childids;
3195
	}
3196
3197
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3198
	/**
3199
	 *	For user id_user and its childs available in this->users, define property fullpath and fullname.
3200
	 *  Function called by get_full_tree().
3201
	 *
3202
	 * 	@param		int		$id_user		id_user entry to update
3203
	 * 	@param		int		$protection		Deep counter to avoid infinite loop (no more required, a protection is added with array useridfound)
3204
	 *	@return		int                     < 0 if KO (infinit loop), >= 0 if OK
3205
	 */
3206
	public function build_path_from_id_user($id_user, $protection = 0)
3207
	{
3208
		// phpcs:enable
3209
		//dol_syslog(get_class($this)."::build_path_from_id_user id_user=".$id_user." protection=".$protection, LOG_DEBUG);
3210
3211
		if (!empty($this->users[$id_user]['fullpath'])) {
3212
			// Already defined
3213
			dol_syslog(get_class($this)."::build_path_from_id_user fullpath and fullname already defined", LOG_WARNING);
3214
			return 0;
3215
		}
3216
3217
		// Define fullpath and fullname
3218
		$this->users[$id_user]['fullpath'] = '_'.$id_user;
3219
		$this->users[$id_user]['fullname'] = $this->users[$id_user]['lastname'];
3220
		$i = 0; $cursor_user = $id_user;
3221
3222
		$useridfound = array($id_user);
3223
		while (!empty($this->parentof[$cursor_user])) {
3224
			if (in_array($this->parentof[$cursor_user], $useridfound)) {
3225
				dol_syslog("The hierarchy of user has a recursive loop", LOG_WARNING);
3226
				return -1; // Should not happen. Protection against looping hierarchy
3227
			}
3228
			$useridfound[] = $this->parentof[$cursor_user];
3229
			$this->users[$id_user]['fullpath'] = '_'.$this->parentof[$cursor_user].$this->users[$id_user]['fullpath'];
3230
			$this->users[$id_user]['fullname'] = $this->users[$this->parentof[$cursor_user]]['lastname'].' >> '.$this->users[$id_user]['fullname'];
3231
			$i++; $cursor_user = $this->parentof[$cursor_user];
3232
		}
3233
3234
		// We count number of _ to have level
3235
		$this->users[$id_user]['level'] = dol_strlen(preg_replace('/[^_]/i', '', $this->users[$id_user]['fullpath']));
3236
3237
		return 1;
3238
	}
3239
3240
	/**
3241
	 * Function used to replace a thirdparty id with another one.
3242
	 *
3243
	 * @param DoliDB $db Database handler
3244
	 * @param int $origin_id Old thirdparty id
3245
	 * @param int $dest_id New thirdparty id
3246
	 * @return bool
3247
	 */
3248
	public static function replaceThirdparty(DoliDB $db, $origin_id, $dest_id)
3249
	{
3250
		$tables = array(
3251
			'user',
3252
		);
3253
3254
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
3255
	}
3256
3257
3258
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3259
	/**
3260
	 *      Load metrics this->nb for dashboard
3261
	 *
3262
	 *      @return     int         <0 if KO, >0 if OK
3263
	 */
3264
	public function load_state_board()
3265
	{
3266
		// phpcs:enable
3267
3268
		$this->nb = array();
3269
3270
		$sql = "SELECT count(u.rowid) as nb";
3271
		$sql .= " FROM ".MAIN_DB_PREFIX."user as u";
3272
		$sql .= " WHERE u.statut > 0";
3273
		//$sql.= " AND employee != 0";
3274
		$sql .= " AND u.entity IN (".getEntity('user').")";
3275
3276
		$resql = $this->db->query($sql);
3277
		if ($resql) {
3278
			while ($obj = $this->db->fetch_object($resql)) {
3279
				$this->nb["users"] = $obj->nb;
3280
			}
3281
			$this->db->free($resql);
3282
			return 1;
3283
		} else {
3284
			dol_print_error($this->db);
3285
			$this->error = $this->db->error();
3286
			return -1;
3287
		}
3288
	}
3289
3290
	/**
3291
	 *  Create a document onto disk according to template module.
3292
	 *
3293
	 * 	@param	    string		$modele			Force model to use ('' to not force)
3294
	 * 	@param		Translate	$outputlangs	Object langs to use for output
3295
	 *  @param      int			$hidedetails    Hide details of lines
3296
	 *  @param      int			$hidedesc       Hide description
3297
	 *  @param      int			$hideref        Hide ref
3298
	 *  @param   null|array  $moreparams     Array to provide more information
3299
	 * 	@return     int         				0 if KO, 1 if OK
3300
	 */
3301
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
3302
	{
3303
		global $conf, $user, $langs;
3304
3305
		$langs->load("user");
3306
3307
		// Positionne le modele sur le nom du modele a utiliser
3308
		if (!dol_strlen($modele)) {
3309
			if (!empty($conf->global->USER_ADDON_PDF)) {
3310
				$modele = $conf->global->USER_ADDON_PDF;
3311
			} else {
3312
				$modele = 'bluesky';
3313
			}
3314
		}
3315
3316
		$modelpath = "core/modules/user/doc/";
3317
3318
		return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
3319
	}
3320
3321
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
3322
	/**
3323
	 *  Return property of user from its id
3324
	 *
3325
	 *  @param	int		$rowid      id of contact
3326
	 *  @param  string	$mode       'email' or 'mobile'
3327
	 *  @return string  			Email of user with format: "Full name <email>"
3328
	 */
3329
	public function user_get_property($rowid, $mode)
3330
	{
3331
		// phpcs:enable
3332
		$user_property = '';
3333
3334
		if (empty($rowid)) {
3335
			return '';
3336
		}
3337
3338
		$sql = "SELECT rowid, email, user_mobile, civility, lastname, firstname";
3339
		$sql .= " FROM ".MAIN_DB_PREFIX."user";
3340
		$sql .= " WHERE rowid = ".((int) $rowid);
3341
3342
		$resql = $this->db->query($sql);
3343
		if ($resql) {
3344
			$nump = $this->db->num_rows($resql);
3345
3346
			if ($nump) {
3347
				$obj = $this->db->fetch_object($resql);
3348
3349
				if ($mode == 'email') {
3350
					$user_property = dolGetFirstLastname($obj->firstname, $obj->lastname)." <".$obj->email.">";
3351
				} elseif ($mode == 'mobile') {
3352
					$user_property = $obj->user_mobile;
3353
				}
3354
			}
3355
			return $user_property;
3356
		} else {
3357
			dol_print_error($this->db);
3358
		}
3359
	}
3360
3361
	/**
3362
	 *	Load all objects into $this->users
3363
	 *
3364
	 *  @param	string		$sortorder		sort order
3365
	 *  @param	string		$sortfield		sort field
3366
	 *  @param	int			$limit			limit page
3367
	 *  @param	int			$offset			page
3368
	 *  @param	array		$filter			Filter array. Example array('field'=>'valueforlike', 'customurl'=>...)
3369
	 *  @param  string      $filtermode		Filter mode (AND or OR)
3370
	 *  @param  bool        $entityfilter	Activate entity filter
3371
	 *  @return int							<0 if KO, >0 if OK
3372
	 */
3373
	public function fetchAll($sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = array(), $filtermode = 'AND', $entityfilter = false)
3374
	{
3375
		global $conf, $user;
3376
3377
		$sql = "SELECT t.rowid";
3378
		$sql .= ' FROM '.MAIN_DB_PREFIX.$this->table_element.' as t ';
3379
3380
		if ($entityfilter) {
3381
			if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
3382
				if (!empty($user->admin) && empty($user->entity) && $conf->entity == 1) {
3383
					$sql .= " WHERE t.entity IS NOT NULL"; // Show all users
3384
				} else {
3385
					$sql .= ",".MAIN_DB_PREFIX."usergroup_user as ug";
3386
					$sql .= " WHERE ((ug.fk_user = t.rowid";
3387
					$sql .= " AND ug.entity IN (".getEntity('user')."))";
3388
					$sql .= " OR t.entity = 0)"; // Show always superadmin
3389
				}
3390
			} else {
3391
				$sql .= " WHERE t.entity IN (".getEntity('user').")";
3392
			}
3393
		} else {
3394
			$sql .= " WHERE 1";
3395
		}
3396
3397
		// Manage filter
3398
		$sqlwhere = array();
3399
		if (!empty($filter)) {
3400
			foreach ($filter as $key => $value) {
3401
				if ($key == 't.rowid') {
3402
					$sqlwhere[] = $key.'='.$value;
3403
				} elseif (strpos($key, 'date') !== false) {
3404
					$sqlwhere[] = $key.' = \''.$this->db->idate($value).'\'';
3405
				} elseif ($key == 'customsql') {
3406
					$sqlwhere[] = $value;
3407
				} else {
3408
					$sqlwhere[] = $key.' LIKE \'%'.$this->db->escape($value).'%\'';
3409
				}
3410
			}
3411
		}
3412
		if (count($sqlwhere) > 0) {
3413
			$sql .= ' AND ('.implode(' '.$filtermode.' ', $sqlwhere).')';
3414
		}
3415
		$sql .= $this->db->order($sortfield, $sortorder);
3416
		if ($limit) {
3417
			$sql .= $this->db->plimit($limit + 1, $offset);
3418
		}
3419
3420
		dol_syslog(__METHOD__, LOG_DEBUG);
3421
3422
		$resql = $this->db->query($sql);
3423
		if ($resql) {
3424
			$this->users = array();
3425
			$num = $this->db->num_rows($resql);
3426
			if ($num) {
3427
				while ($obj = $this->db->fetch_object($resql)) {
3428
					$line = new self($this->db);
3429
					$result = $line->fetch($obj->rowid);
3430
					if ($result > 0 && !empty($line->id)) {
3431
						$this->users[$obj->rowid] = clone $line;
3432
					}
3433
				}
3434
				$this->db->free($resql);
3435
			}
3436
			return $num;
3437
		} else {
3438
			$this->errors[] = $this->db->lasterror();
3439
			return -1;
3440
		}
3441
	}
3442
3443
	/**
3444
	 * Cache the SQL results of the function "findUserIdByEmail($email)"
3445
	 *
3446
	 * NOTE: findUserIdByEmailCache[...] === -1 means not found in database
3447
	 *
3448
	 * @var array
3449
	 */
3450
	private $findUserIdByEmailCache;
3451
3452
	/**
3453
	 * Find a user by the given e-mail and return it's user id when found
3454
	 *
3455
	 * NOTE:
3456
	 * Use AGENDA_DISABLE_EXACT_USER_EMAIL_COMPARE_FOR_EXTERNAL_CALENDAR
3457
	 * to disable exact e-mail search
3458
	 *
3459
	 * @param string	$email	The full e-mail (or a part of a e-mail)
3460
	 * @return int				<0 = user was not found, >0 = The id of the user
3461
	 */
3462
	public function findUserIdByEmail($email)
3463
	{
3464
		if ($this->findUserIdByEmailCache[$email]) {
3465
			return $this->findUserIdByEmailCache[$email];
3466
		}
3467
3468
		$this->findUserIdByEmailCache[$email] = -1;
3469
3470
		global $conf;
3471
3472
		$sql = 'SELECT rowid';
3473
		$sql .= ' FROM '.MAIN_DB_PREFIX.'user';
3474
3475
		if (!empty($conf->global->AGENDA_DISABLE_EXACT_USER_EMAIL_COMPARE_FOR_EXTERNAL_CALENDAR)) {
3476
			$sql .= ' WHERE email LIKE "%'.$email.'%"';
3477
		} else {
3478
			$sql .= ' WHERE email = "'.$email.'"';
3479
		}
3480
3481
		$sql .= ' LIMIT 1';
3482
3483
		$resql = $this->db->query($sql);
3484
		if (!$resql) {
3485
			return -1;
3486
		}
3487
3488
		$obj = $this->db->fetch_object($resql);
3489
		if (!$obj) {
3490
			return -1;
3491
		}
3492
3493
		$this->findUserIdByEmailCache[$email] = (int) $obj->rowid;
3494
3495
		return $this->findUserIdByEmailCache[$email];
3496
	}
3497
}
3498