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

User::send_password()   B

Complexity

Conditions 7
Paths 32

Size

Total Lines 94
Code Lines 62

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 62
nc 32
nop 3
dl 0
loc 94
rs 7.8957
c 0
b 0
f 0

How to fix   Long Method   

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:

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