Passed
Branch develop (f6c1a1)
by
unknown
28:54
created

User::getNomUrl()   D

Complexity

Conditions 54
Paths 0

Size

Total Lines 128
Code Lines 84

Duplication

Lines 0
Ratio 0 %

Importance

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