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

User::getNomUrl()   D

Complexity

Conditions 52
Paths 0

Size

Total Lines 127
Code Lines 83

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 52
eloc 83
c 0
b 0
f 0
nc 0
nop 9
dl 0
loc 127
rs 4.1666

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

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

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

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

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

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

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

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

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

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

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

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

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