5744 lines
199 KiB
PHP
5744 lines
199 KiB
PHP
<?php
|
|
/**
|
|
* ---------------------------------------------------------------------
|
|
* GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2015-2020 Teclib' and contributors.
|
|
*
|
|
* http://glpi-project.org
|
|
*
|
|
* based on GLPI - Gestionnaire Libre de Parc Informatique
|
|
* Copyright (C) 2003-2014 by the INDEPNET Development Team.
|
|
*
|
|
* ---------------------------------------------------------------------
|
|
*
|
|
* LICENSE
|
|
*
|
|
* This file is part of GLPI.
|
|
*
|
|
* GLPI is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* GLPI is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GLPI. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
|
|
if (!defined('GLPI_ROOT')) {
|
|
die("Sorry. You can't access this file directly");
|
|
}
|
|
|
|
use Sabre\VObject;
|
|
use Glpi\Exception\ForgetPasswordException;
|
|
use Glpi\Exception\PasswordTooWeakException;
|
|
|
|
|
|
|
|
class User extends CommonDBTM {
|
|
|
|
// From CommonDBTM
|
|
public $dohistory = true;
|
|
public $history_blacklist = ['date_mod', 'date_sync', 'last_login',
|
|
'publicbookmarkorder', 'privatebookmarkorder'];
|
|
|
|
// NAME FIRSTNAME ORDER TYPE
|
|
const REALNAME_BEFORE = 0;
|
|
const FIRSTNAME_BEFORE = 1;
|
|
|
|
const IMPORTEXTAUTHUSERS = 1024;
|
|
const READAUTHENT = 2048;
|
|
const UPDATEAUTHENT = 4096;
|
|
|
|
static $rightname = 'user';
|
|
|
|
static $undisclosedFields = [
|
|
'password',
|
|
'personal_token',
|
|
'api_token',
|
|
'cookie_token',
|
|
];
|
|
|
|
private $entities = null;
|
|
|
|
|
|
static function getTypeName($nb = 0) {
|
|
return _n('User', 'Users', $nb);
|
|
}
|
|
|
|
static function getMenuShorcut() {
|
|
return 'u';
|
|
}
|
|
|
|
static function getAdditionalMenuOptions() {
|
|
|
|
if (Session::haveRight('user', self::IMPORTEXTAUTHUSERS)) {
|
|
return [
|
|
'ldap' => [
|
|
'title' => AuthLDAP::getTypeName(Session::getPluralNumber()),
|
|
'page' => '/front/ldap.php',
|
|
],
|
|
];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function canViewItem() {
|
|
if (Session::canViewAllEntities()
|
|
|| Session::haveAccessToOneOfEntities($this->getEntities())) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function canCreateItem() {
|
|
|
|
// Will be created from form, with selected entity/profile
|
|
if (isset($this->input['_profiles_id']) && ($this->input['_profiles_id'] > 0)
|
|
&& Profile::currentUserHaveMoreRightThan([$this->input['_profiles_id']])
|
|
&& isset($this->input['_entities_id'])
|
|
&& Session::haveAccessToEntity($this->input['_entities_id'])) {
|
|
return true;
|
|
}
|
|
// Will be created with default value
|
|
if (Session::haveAccessToEntity(0) // Access to root entity (required when no default profile)
|
|
|| (Profile::getDefault() > 0)) {
|
|
return true;
|
|
}
|
|
|
|
if (($_SESSION['glpiactive_entity'] > 0)
|
|
&& (Profile::getDefault() == 0)) {
|
|
echo "<div class='tab_cadre_fixe warning'>".
|
|
__('You must define a default profile to create a new user')."</div>";
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
function canUpdateItem() {
|
|
|
|
$entities = Profile_User::getUserEntities($this->fields['id'], false);
|
|
if (Session::canViewAllEntities()
|
|
|| Session::haveAccessToOneOfEntities($entities)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function canDeleteItem() {
|
|
if (Session::canViewAllEntities()
|
|
|| Session::haveAccessToAllOfEntities($this->getEntities())) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function canPurgeItem() {
|
|
return $this->canDeleteItem();
|
|
}
|
|
|
|
|
|
function isEntityAssign() {
|
|
// glpi_users.entities_id is only a pref.
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Compute preferences for the current user mixing config and user data.
|
|
*
|
|
* @return void
|
|
*/
|
|
function computePreferences() {
|
|
global $CFG_GLPI;
|
|
|
|
if (isset($this->fields['id'])) {
|
|
foreach ($CFG_GLPI['user_pref_field'] as $f) {
|
|
if (is_null($this->fields[$f])) {
|
|
$this->fields[$f] = $CFG_GLPI[$f];
|
|
}
|
|
}
|
|
}
|
|
/// Specific case for show_count_on_tabs : global config can forbid
|
|
if ($CFG_GLPI['show_count_on_tabs'] == -1) {
|
|
$this->fields['show_count_on_tabs'] = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Load minimal session for user.
|
|
*
|
|
* @param integer $entities_id Entity to use
|
|
* @param boolean $is_recursive Whether to load entities recursivly or not
|
|
*
|
|
* @return void
|
|
*
|
|
* @since 0.83.7
|
|
*/
|
|
function loadMinimalSession($entities_id, $is_recursive) {
|
|
global $CFG_GLPI;
|
|
|
|
if (isset($this->fields['id']) && !isset($_SESSION["glpiID"])) {
|
|
Session::destroy();
|
|
Session::start();
|
|
$_SESSION["glpiID"] = $this->fields['id'];
|
|
$_SESSION["glpi_use_mode"] = Session::NORMAL_MODE;
|
|
$_SESSION["glpiactive_entity"] = $entities_id;
|
|
$_SESSION["glpiactive_entity_recursive"] = $is_recursive;
|
|
if ($is_recursive) {
|
|
$entities = getSonsOf("glpi_entities", $entities_id);
|
|
} else {
|
|
$entities = [$entities_id];
|
|
}
|
|
$_SESSION['glpiactiveentities'] = $entities;
|
|
$_SESSION['glpiactiveentities_string'] = "'".implode("', '", $entities)."'";
|
|
$this->computePreferences();
|
|
foreach ($CFG_GLPI['user_pref_field'] as $field) {
|
|
if (isset($this->fields[$field])) {
|
|
$_SESSION["glpi$field"] = $this->fields[$field];
|
|
}
|
|
}
|
|
Session::loadGroups();
|
|
Session::loadLanguage();
|
|
}
|
|
}
|
|
|
|
|
|
function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) {
|
|
|
|
switch ($item->getType()) {
|
|
case __CLASS__ :
|
|
$ong = [];
|
|
$ong[1] = __('Used items');
|
|
$ong[2] = __('Managed items');
|
|
return $ong;
|
|
|
|
case 'Preference' :
|
|
return __('Main');
|
|
}
|
|
return '';
|
|
}
|
|
|
|
|
|
static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) {
|
|
global $CFG_GLPI;
|
|
|
|
switch ($item->getType()) {
|
|
case __CLASS__ :
|
|
$item->showItems($tabnum==2);
|
|
return true;
|
|
|
|
case 'Preference' :
|
|
$user = new self();
|
|
$user->showMyForm($CFG_GLPI['root_doc']."/front/preference.php",
|
|
Session::getLoginUserID());
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
function defineTabs($options = []) {
|
|
|
|
$ong = [];
|
|
$this->addDefaultFormTab($ong);
|
|
$this->addImpactTab($ong, $options);
|
|
$this->addStandardTab('Profile_User', $ong, $options);
|
|
$this->addStandardTab('Group_User', $ong, $options);
|
|
$this->addStandardTab('Config', $ong, $options);
|
|
$this->addStandardTab(__CLASS__, $ong, $options);
|
|
$this->addStandardTab('Ticket', $ong, $options);
|
|
$this->addStandardTab('Item_Problem', $ong, $options);
|
|
$this->addStandardTab('Change_Item', $ong, $options);
|
|
$this->addStandardTab('Document_Item', $ong, $options);
|
|
$this->addStandardTab('Reservation', $ong, $options);
|
|
$this->addStandardTab('Auth', $ong, $options);
|
|
$this->addStandardTab('Link', $ong, $options);
|
|
$this->addStandardTab('Certificate_Item', $ong, $options);
|
|
$this->addStandardTab('Log', $ong, $options);
|
|
|
|
return $ong;
|
|
}
|
|
|
|
|
|
function post_getEmpty() {
|
|
global $CFG_GLPI;
|
|
|
|
$this->fields["is_active"] = 1;
|
|
if (isset($CFG_GLPI["language"])) {
|
|
$this->fields['language'] = $CFG_GLPI["language"];
|
|
} else {
|
|
$this->fields['language'] = "en_GB";
|
|
}
|
|
}
|
|
|
|
|
|
function pre_deleteItem() {
|
|
global $DB;
|
|
|
|
$entities = $this->getEntities();
|
|
$view_all = Session::canViewAllEntities();
|
|
// Have right on all entities ?
|
|
$all = true;
|
|
if (!$view_all) {
|
|
foreach ($entities as $ent) {
|
|
if (!Session::haveAccessToEntity($ent)) {
|
|
$all = false;
|
|
}
|
|
}
|
|
}
|
|
if ($all) { // Mark as deleted
|
|
return true;
|
|
}
|
|
// only delete profile
|
|
foreach ($entities as $ent) {
|
|
if (Session::haveAccessToEntity($ent)) {
|
|
$all = false;
|
|
$DB->delete(
|
|
'glpi_profiles_users', [
|
|
'users_id' => $this->fields['id'],
|
|
'entities_id' => $ent
|
|
]
|
|
);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
function cleanDBonPurge() {
|
|
|
|
global $DB;
|
|
|
|
// ObjectLock does not extends CommonDBConnexity
|
|
$ol = new ObjectLock();
|
|
$ol->deleteByCriteria(['users_id' => $this->fields['id']]);
|
|
|
|
// Reminder does not extends CommonDBConnexity
|
|
$r = new Reminder();
|
|
$r->deleteByCriteria(['users_id' => $this->fields['id']]);
|
|
|
|
// Delete private bookmark
|
|
$ss = new SavedSearch();
|
|
$ss->deleteByCriteria(
|
|
[
|
|
'users_id' => $this->fields['id'],
|
|
'is_private' => 1,
|
|
]
|
|
);
|
|
|
|
// Set no user to public bookmark
|
|
$DB->update(
|
|
SavedSearch::getTable(), [
|
|
'users_id' => 0
|
|
], [
|
|
'users_id' => $this->fields['id']
|
|
]
|
|
);
|
|
|
|
// Set no user to consumables
|
|
$DB->update(
|
|
'glpi_consumables', [
|
|
'items_id' => 0,
|
|
'itemtype' => 'NULL',
|
|
'date_out' => 'NULL'
|
|
], [
|
|
'items_id' => $this->fields['id'],
|
|
'itemtype' => 'User'
|
|
]
|
|
);
|
|
|
|
$this->deleteChildrenAndRelationsFromDb(
|
|
[
|
|
Certificate_Item::class,
|
|
Change_User::class,
|
|
Group_User::class,
|
|
KnowbaseItem_User::class,
|
|
Problem_User::class,
|
|
Profile_User::class,
|
|
ProjectTaskTeam::class,
|
|
ProjectTeam::class,
|
|
Reminder_User::class,
|
|
RSSFeed_User::class,
|
|
SavedSearch_User::class,
|
|
Ticket_User::class,
|
|
UserEmail::class,
|
|
]
|
|
);
|
|
|
|
if ($this->fields['id'] > 0) { // Security
|
|
// DisplayPreference does not extends CommonDBConnexity
|
|
$dp = new DisplayPreference();
|
|
$dp->deleteByCriteria(['users_id' => $this->fields['id']]);
|
|
}
|
|
|
|
$this->dropPictureFiles($this->fields['picture']);
|
|
|
|
// Ticket rules use various _users_id_*
|
|
Rule::cleanForItemAction($this, '_users_id%');
|
|
Rule::cleanForItemCriteria($this, '_users_id%');
|
|
|
|
// Alert does not extends CommonDBConnexity
|
|
$alert = new Alert();
|
|
$alert->cleanDBonItemDelete($this->getType(), $this->fields['id']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve a user from the database using its login.
|
|
*
|
|
* @param string $name Login of the user
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function getFromDBbyName($name) {
|
|
return $this->getFromDBByCrit(['name' => $name]);
|
|
}
|
|
|
|
/**
|
|
* Retrieve a user from the database using its login.
|
|
*
|
|
* @param string $name Login of the user
|
|
* @param integer $authtype Auth type (see Auth constants)
|
|
* @param integer $auths_id ID of auth server
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function getFromDBbyNameAndAuth($name, $authtype, $auths_id) {
|
|
return $this->getFromDBByCrit([
|
|
'name' => $name,
|
|
'authtype' => $authtype,
|
|
'auths_id' => $auths_id
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Retrieve a user from the database using value of the sync field.
|
|
*
|
|
* @param string $value Value of the sync field
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function getFromDBbySyncField($value) {
|
|
return $this->getFromDBByCrit(['sync_field' => $value]);
|
|
}
|
|
|
|
/**
|
|
* Retrieve a user from the database using it's dn.
|
|
*
|
|
* @since 0.84
|
|
*
|
|
* @param string $user_dn dn of the user
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function getFromDBbyDn($user_dn) {
|
|
return $this->getFromDBByCrit(['user_dn' => $user_dn]);
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve a user from the database using its email.
|
|
*
|
|
* @since 9.3 Can pass condition as a parameter
|
|
*
|
|
* @param string $email user email
|
|
* @param array $condition add condition
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function getFromDBbyEmail($email, $condition = []) {
|
|
global $DB;
|
|
|
|
$crit = [
|
|
'SELECT' => $this->getTable() . '.id',
|
|
'FROM' => $this->getTable(),
|
|
'LEFT JOIN' => [
|
|
'glpi_useremails' => [
|
|
'FKEY' => [
|
|
$this->getTable() => 'id',
|
|
'glpi_useremails' => 'users_id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => ['glpi_useremails.email' => $email] + $condition
|
|
];
|
|
|
|
$iter = $DB->request($crit);
|
|
if ($iter->numrows()==1) {
|
|
$row = $iter->next();
|
|
return $this->getFromDB($row['id']);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get the default email of the user.
|
|
*
|
|
* @return string
|
|
*/
|
|
function getDefaultEmail() {
|
|
|
|
if (!isset($this->fields['id'])) {
|
|
return '';
|
|
}
|
|
|
|
return UserEmail::getDefaultForUser($this->fields['id']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all emails of the user.
|
|
*
|
|
* @return string[]
|
|
*/
|
|
function getAllEmails() {
|
|
|
|
if (!isset($this->fields['id'])) {
|
|
return [];
|
|
}
|
|
return UserEmail::getAllForUser($this->fields['id']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if the email is attached to the current user.
|
|
*
|
|
* @param string $email
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function isEmail($email) {
|
|
|
|
if (!isset($this->fields['id'])) {
|
|
return false;
|
|
}
|
|
return UserEmail::isEmailForUser($this->fields['id'], $email);
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve a user from the database using its personal token.
|
|
*
|
|
* @param string $token user token
|
|
* @param string $field the field storing the token
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function getFromDBbyToken($token, $field = 'personal_token') {
|
|
$fields = ['personal_token', 'api_token'];
|
|
if (!in_array($field, $fields)) {
|
|
Toolbox::logWarning('User::getFromDBbyToken() can only be called with $field parameter with theses values: \'' . implode('\', \'', $fields) . '\'');
|
|
return false;
|
|
}
|
|
|
|
return $this->getFromDBByCrit([$this->getTable() . ".$field" => $token]);
|
|
}
|
|
|
|
|
|
function prepareInputForAdd($input) {
|
|
global $DB;
|
|
|
|
if (isset($input['_stop_import'])) {
|
|
return false;
|
|
}
|
|
|
|
if (!Auth::isValidLogin(stripslashes($input['name']))) {
|
|
Session::addMessageAfterRedirect(__('The login is not valid. Unable to add the user.'),
|
|
false, ERROR);
|
|
return false;
|
|
}
|
|
|
|
// avoid xss (picture field is autogenerated)
|
|
if (isset($input['picture'])) {
|
|
$input['picture'] = 'NULL';
|
|
}
|
|
|
|
if (!isset($input["authtype"])) {
|
|
$input["authtype"] = Auth::DB_GLPI;
|
|
}
|
|
|
|
if (!isset($input["auths_id"])) {
|
|
$input["auths_id"] = 0;
|
|
}
|
|
|
|
// Check if user does not exists
|
|
$iterator = $DB->request([
|
|
'FROM' => $this->getTable(),
|
|
'WHERE' => [
|
|
'name' => $input['name'],
|
|
'authtype' => $input['authtype'],
|
|
'auths_id' => $input['auths_id']
|
|
],
|
|
'LIMIT' => 1
|
|
]);
|
|
|
|
if (count($iterator)) {
|
|
Session::addMessageAfterRedirect(__('Unable to add. The user already exists.'),
|
|
false, ERROR);
|
|
return false;
|
|
}
|
|
|
|
if (isset($input["password2"])) {
|
|
if (empty($input["password"])) {
|
|
unset ($input["password"]);
|
|
|
|
} else {
|
|
if ($input["password"] == $input["password2"]) {
|
|
if (Config::validatePassword($input["password"])) {
|
|
$input["password"]
|
|
= Auth::getPasswordHash(Toolbox::unclean_cross_side_scripting_deep(stripslashes($input["password"])));
|
|
|
|
$input['password_last_update'] = $_SESSION['glpi_currenttime'];
|
|
} else {
|
|
unset($input["password"]);
|
|
}
|
|
unset($input["password2"]);
|
|
} else {
|
|
Session::addMessageAfterRedirect(__('Error: the two passwords do not match'),
|
|
false, ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($input["_extauth"])) {
|
|
$input["password"] = "";
|
|
}
|
|
|
|
// Force DB default values : not really needed
|
|
if (!isset($input["is_active"])) {
|
|
$input["is_active"] = 1;
|
|
}
|
|
|
|
if (!isset($input["is_deleted"])) {
|
|
$input["is_deleted"] = 0;
|
|
}
|
|
|
|
if (!isset($input["entities_id"])) {
|
|
$input["entities_id"] = 0;
|
|
}
|
|
|
|
if (!isset($input["profiles_id"])) {
|
|
$input["profiles_id"] = 0;
|
|
}
|
|
|
|
return $input;
|
|
}
|
|
|
|
public function prepareInputForClone($input) {
|
|
if (isset($input['name'])) {
|
|
$suffix = 1;
|
|
$possibleName = $input['name'].$suffix;
|
|
while ($this->getFromDBbyName($possibleName)) {
|
|
$suffix++;
|
|
$possibleName = $input['name'].$suffix;
|
|
}
|
|
$input['name'] = $possibleName;
|
|
}
|
|
return $input;
|
|
}
|
|
|
|
|
|
function post_addItem() {
|
|
|
|
$this->updateUserEmails();
|
|
$this->syncLdapGroups();
|
|
$this->syncDynamicEmails();
|
|
|
|
$this->applyGroupsRules();
|
|
$rulesplayed = $this->applyRightRules();
|
|
$picture = $this->syncLdapPhoto();
|
|
|
|
//add picture in user fields
|
|
if (!empty($picture)) {
|
|
$this->update(['id' => $this->fields['id'],
|
|
'picture' => $picture]);
|
|
}
|
|
|
|
// Add default profile
|
|
if (!$rulesplayed) {
|
|
$affectation = [];
|
|
if (isset($this->input['_profiles_id']) && $this->input['_profiles_id']
|
|
&& Profile::currentUserHaveMoreRightThan([$this->input['_profiles_id']])
|
|
) {
|
|
$profile = $this->input['_profiles_id'];
|
|
// Choosen in form, so not dynamic
|
|
$affectation['is_dynamic'] = 0;
|
|
} else {
|
|
$profile = Profile::getDefault();
|
|
// Default right as dynamic. If dynamic rights are set it will disappear.
|
|
$affectation['is_dynamic'] = 1;
|
|
}
|
|
|
|
if ($profile) {
|
|
if (isset($this->input["_entities_id"])) {
|
|
// entities_id (user's pref) always set in prepareInputForAdd
|
|
// use _entities_id for default right
|
|
$affectation["entities_id"] = $this->input["_entities_id"];
|
|
|
|
} else if (isset($_SESSION['glpiactive_entity'])) {
|
|
$affectation["entities_id"] = $_SESSION['glpiactive_entity'];
|
|
|
|
} else {
|
|
$affectation["entities_id"] = 0;
|
|
}
|
|
if (isset($this->input["_is_recursive"])) {
|
|
$affectation["is_recursive"] = $this->input["_is_recursive"];
|
|
} else {
|
|
$affectation["is_recursive"] = 0;
|
|
}
|
|
|
|
$affectation["profiles_id"] = $profile;
|
|
$affectation["users_id"] = $this->fields["id"];
|
|
$right = new Profile_User();
|
|
$right->add($affectation);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function prepareInputForUpdate($input) {
|
|
global $CFG_GLPI;
|
|
|
|
// avoid xss (picture name is autogenerated when uploading/synchronising the picture)
|
|
unset($input['picture']);
|
|
|
|
//picture manually uploaded by user
|
|
if (isset($input["_blank_picture"]) && $input["_blank_picture"]) {
|
|
self::dropPictureFiles($this->fields['picture']);
|
|
$input['picture'] = 'NULL';
|
|
} else {
|
|
$newPicture = false;
|
|
if (!isAPI()) {
|
|
if (isset($input["_picture"][0]) && !empty($input["_picture"][0])) {
|
|
$input["_picture"] = $input["_picture"][0];
|
|
}
|
|
}
|
|
if (isset($input["_picture"]) && !empty($input["_picture"])) {
|
|
$newPicture = true;
|
|
}
|
|
if ($newPicture) {
|
|
$fullpath = GLPI_TMP_DIR."/".$input["_picture"];
|
|
if (Toolbox::getMime($fullpath, 'image')) {
|
|
// Unlink old picture (clean on changing format)
|
|
self::dropPictureFiles($this->fields['picture']);
|
|
// Move uploaded file
|
|
$filename = uniqid($this->fields['id'].'_');
|
|
$sub = substr($filename, -2); /* 2 hex digit */
|
|
|
|
// output images with possible transparency to png, other to jpg
|
|
$extension = strtolower(pathinfo($fullpath, PATHINFO_EXTENSION));
|
|
$extension = in_array($extension, ['png', 'gif'])
|
|
? 'png'
|
|
: 'jpg';
|
|
|
|
@mkdir(GLPI_PICTURE_DIR . "/$sub");
|
|
$picture_path = GLPI_PICTURE_DIR . "/$sub/${filename}.$extension";
|
|
self::dropPictureFiles("$sub/${filename}.$extension");
|
|
|
|
if (Document::isImage($fullpath)
|
|
&& Document::renameForce($fullpath, $picture_path)) {
|
|
Session::addMessageAfterRedirect(__('The file is valid. Upload is successful.'));
|
|
// For display
|
|
$input['picture'] = "$sub/${filename}.$extension";
|
|
|
|
//prepare a thumbnail
|
|
$thumb_path = GLPI_PICTURE_DIR . "/$sub/${filename}_min.$extension";
|
|
Toolbox::resizePicture($picture_path, $thumb_path);
|
|
} else {
|
|
Session::addMessageAfterRedirect(__('Potential upload attack or file too large. Moving temporary file failed.'),
|
|
false, ERROR);
|
|
}
|
|
} else {
|
|
Session::addMessageAfterRedirect(__('The file is not an image file.'),
|
|
false, ERROR);
|
|
}
|
|
} else {
|
|
//ldap jpegphoto synchronisation.
|
|
$picture = $this->syncLdapPhoto();
|
|
if (!empty($picture)) {
|
|
$input['picture'] = $picture;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($input["password2"])) {
|
|
// Empty : do not update
|
|
if (empty($input["password"])) {
|
|
unset($input["password"]);
|
|
|
|
} else {
|
|
if ($input["password"] == $input["password2"]) {
|
|
// Check right : my password of user with lesser rights
|
|
if (isset($input['id'])
|
|
&& !Auth::checkPassword($input['password'], $this->fields['password']) // Validate that password is not same as previous
|
|
&& Config::validatePassword($input["password"])
|
|
&& (($input['id'] == Session::getLoginUserID())
|
|
|| $this->currentUserHaveMoreRightThan($input['id'])
|
|
// Permit to change password with token and email
|
|
|| (($input['password_forget_token'] == $this->fields['password_forget_token'])
|
|
&& (abs(strtotime($_SESSION["glpi_currenttime"])
|
|
-strtotime($this->fields['password_forget_token_date'])) < DAY_TIMESTAMP)
|
|
&& $this->isEmail($input['email'])))) {
|
|
$input["password"]
|
|
= Auth::getPasswordHash(Toolbox::unclean_cross_side_scripting_deep(stripslashes($input["password"])));
|
|
|
|
$input['password_last_update'] = $_SESSION["glpi_currenttime"];
|
|
} else {
|
|
unset($input["password"]);
|
|
}
|
|
unset($input["password2"]);
|
|
|
|
} else {
|
|
Session::addMessageAfterRedirect(__('Error: the two passwords do not match'),
|
|
false, ERROR);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
} else if (isset($input["password"])) { // From login
|
|
unset($input["password"]);
|
|
}
|
|
|
|
// blank password when authtype changes
|
|
if (isset($input["authtype"])
|
|
&& $input["authtype"] != Auth::DB_GLPI
|
|
&& $input["authtype"] != $this->getField('authtype')) {
|
|
$input["password"] = "";
|
|
}
|
|
|
|
// Update User in the database
|
|
if (!isset($input["id"])
|
|
&& isset($input["name"])) {
|
|
if ($this->getFromDBbyName($input["name"])) {
|
|
$input["id"] = $this->fields["id"];
|
|
}
|
|
}
|
|
|
|
if (isset($input["entities_id"])
|
|
&& (Session::getLoginUserID() == $input['id'])) {
|
|
$_SESSION["glpidefault_entity"] = $input["entities_id"];
|
|
}
|
|
|
|
// Security on default profile update
|
|
if (isset($input['profiles_id'])) {
|
|
if (!in_array($input['profiles_id'], Profile_User::getUserProfiles($input['id']))) {
|
|
unset($input['profiles_id']);
|
|
}
|
|
}
|
|
|
|
// Security on default entity update
|
|
if (isset($input['entities_id'])) {
|
|
if (!in_array($input['entities_id'], Profile_User::getUserEntities($input['id']))) {
|
|
unset($input['entities_id']);
|
|
}
|
|
}
|
|
|
|
// Security on default group update
|
|
if (isset($input['groups_id'])
|
|
&& !Group_User::isUserInGroup($input['id'], $input['groups_id'])) {
|
|
unset($input['groups_id']);
|
|
}
|
|
|
|
if (isset($input['_reset_personal_token'])
|
|
&& $input['_reset_personal_token']) {
|
|
$input['personal_token'] = self::getUniqueToken('personal_token');
|
|
$input['personal_token_date'] = $_SESSION['glpi_currenttime'];
|
|
}
|
|
|
|
if (isset($input['_reset_api_token'])
|
|
&& $input['_reset_api_token']) {
|
|
$input['api_token'] = self::getUniqueToken('api_token');
|
|
$input['api_token_date'] = $_SESSION['glpi_currenttime'];
|
|
}
|
|
|
|
// Manage preferences fields
|
|
if (Session::getLoginUserID() == $input['id']) {
|
|
if (isset($input['use_mode'])
|
|
&& ($_SESSION['glpi_use_mode'] != $input['use_mode'])) {
|
|
$_SESSION['glpi_use_mode'] = $input['use_mode'];
|
|
unset($_SESSION['glpimenu']); // Force menu regeneration
|
|
//Session::loadLanguage();
|
|
}
|
|
}
|
|
|
|
foreach ($CFG_GLPI['user_pref_field'] as $f) {
|
|
if (isset($input[$f])) {
|
|
if (Session::getLoginUserID() == $input['id']) {
|
|
if ($_SESSION["glpi$f"] != $input[$f]) {
|
|
$_SESSION["glpi$f"] = $input[$f];
|
|
// reinit translations
|
|
if ($f == 'language') {
|
|
$_SESSION['glpi_dropdowntranslations'] = DropdownTranslation::getAvailableTranslations($_SESSION["glpilanguage"]);
|
|
unset($_SESSION['glpimenu']);
|
|
}
|
|
}
|
|
}
|
|
if ($input[$f] == $CFG_GLPI[$f]) {
|
|
$input[$f] = "NULL";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isset($input['language']) && GLPI_DEMO_MODE) {
|
|
unset($input['language']);
|
|
}
|
|
|
|
if (array_key_exists('timezone', $input) && empty($input['timezone'])) {
|
|
$input['timezone'] = 'NULL';
|
|
}
|
|
|
|
return $input;
|
|
}
|
|
|
|
|
|
function post_updateItem($history = 1) {
|
|
//handle timezone change for current user
|
|
if ($this->fields['id'] == Session::getLoginUserID()) {
|
|
if (null == $this->fields['timezone'] || 'null' === strtolower($this->fields['timezone'])) {
|
|
unset($_SESSION['glpi_tz']);
|
|
} else {
|
|
$_SESSION['glpi_tz'] = $this->fields['timezone'];
|
|
}
|
|
}
|
|
|
|
$this->updateUserEmails();
|
|
$this->syncLdapGroups();
|
|
$this->syncDynamicEmails();
|
|
$this->applyGroupsRules();
|
|
$this->applyRightRules();
|
|
|
|
if (in_array('password', $this->updates)) {
|
|
$alert = new Alert();
|
|
$alert->deleteByCriteria(
|
|
[
|
|
'itemtype' => $this->getType(),
|
|
'items_id' => $this->fields['id'],
|
|
],
|
|
true
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Apply rules to determine dynamic rights of the user.
|
|
*
|
|
* @return boolean true if rules are applied, false otherwise
|
|
*/
|
|
function applyRightRules() {
|
|
|
|
$return = false;
|
|
|
|
if (isset($this->fields['_ruleright_process'])
|
|
|| isset($this->input['_ruleright_process'])) {
|
|
|
|
$dynamic_profiles = Profile_User::getForUser($this->fields["id"], true);
|
|
|
|
if (isset($this->fields["id"])
|
|
&& ($this->fields["id"] > 0)
|
|
&& isset($this->input["_ldap_rules"])
|
|
&& count($this->input["_ldap_rules"])) {
|
|
|
|
//and add/update/delete only if it's necessary !
|
|
if (isset($this->input["_ldap_rules"]["rules_entities_rights"])) {
|
|
$entities_rules = $this->input["_ldap_rules"]["rules_entities_rights"];
|
|
} else {
|
|
$entities_rules = [];
|
|
}
|
|
|
|
if (isset($this->input["_ldap_rules"]["rules_entities"])) {
|
|
$entities = $this->input["_ldap_rules"]["rules_entities"];
|
|
} else {
|
|
$entities = [];
|
|
}
|
|
|
|
if (isset($this->input["_ldap_rules"]["rules_rights"])) {
|
|
$rights = $this->input["_ldap_rules"]["rules_rights"];
|
|
} else {
|
|
$rights = [];
|
|
}
|
|
|
|
$retrieved_dynamic_profiles = [];
|
|
|
|
//For each affectation -> write it in DB
|
|
foreach ($entities_rules as $entity) {
|
|
//Multiple entities assignation
|
|
if (is_array($entity[0])) {
|
|
foreach ($entity[0] as $ent) {
|
|
$retrieved_dynamic_profiles[] = [
|
|
'entities_id' => $ent,
|
|
'profiles_id' => $entity[1],
|
|
'is_recursive' => $entity[2],
|
|
'users_id' => $this->fields['id'],
|
|
'is_dynamic' => 1,
|
|
];
|
|
}
|
|
} else {
|
|
$retrieved_dynamic_profiles[] = [
|
|
'entities_id' => $entity[0],
|
|
'profiles_id' => $entity[1],
|
|
'is_recursive' => $entity[2],
|
|
'users_id' => $this->fields['id'],
|
|
'is_dynamic' => 1,
|
|
];
|
|
}
|
|
}
|
|
|
|
if ((count($entities) > 0)
|
|
&& (count($rights) == 0)) {
|
|
if ($def_prof = Profile::getDefault()) {
|
|
$rights[] = $def_prof;
|
|
}
|
|
}
|
|
|
|
if ((count($rights) > 0)
|
|
&& (count($entities) > 0)) {
|
|
foreach ($rights as $right) {
|
|
foreach ($entities as $entity) {
|
|
$retrieved_dynamic_profiles[] = [
|
|
'entities_id' => $entity[0],
|
|
'profiles_id' => $right,
|
|
'is_recursive' => $entity[1],
|
|
'users_id' => $this->fields['id'],
|
|
'is_dynamic' => 1,
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// Compare retrived profiles to existing ones : clean arrays to do purge and add
|
|
if (count($retrieved_dynamic_profiles)) {
|
|
foreach ($retrieved_dynamic_profiles as $keyretr => $retr_profile) {
|
|
$found = false;
|
|
|
|
foreach ($dynamic_profiles as $keydb => $db_profile) {
|
|
// Found existing profile : unset values in array
|
|
if (!$found
|
|
&& ($db_profile['entities_id'] == $retr_profile['entities_id'])
|
|
&& ($db_profile['profiles_id'] == $retr_profile['profiles_id'])
|
|
&& ($db_profile['is_recursive'] == $retr_profile['is_recursive'])) {
|
|
|
|
unset($retrieved_dynamic_profiles[$keyretr]);
|
|
unset($dynamic_profiles[$keydb]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add new dynamic profiles
|
|
if (count($retrieved_dynamic_profiles)) {
|
|
$right = new Profile_User();
|
|
foreach ($retrieved_dynamic_profiles as $keyretr => $retr_profile) {
|
|
$right->add($retr_profile);
|
|
}
|
|
}
|
|
|
|
//Unset all the temporary tables
|
|
unset($this->input["_ldap_rules"]);
|
|
|
|
$return = true;
|
|
}
|
|
|
|
// Delete old dynamic profiles
|
|
if (count($dynamic_profiles)) {
|
|
$right = new Profile_User();
|
|
foreach ($dynamic_profiles as $keydb => $db_profile) {
|
|
$right->delete($db_profile);
|
|
}
|
|
}
|
|
|
|
}
|
|
return $return;
|
|
}
|
|
|
|
|
|
/**
|
|
* Synchronise LDAP group of the user.
|
|
*
|
|
* @return void
|
|
*/
|
|
function syncLdapGroups() {
|
|
global $DB;
|
|
|
|
// input["_groups"] not set when update from user.form or preference
|
|
if (isset($this->fields["authtype"])
|
|
&& isset($this->input["_groups"])
|
|
&& (($this->fields["authtype"] == Auth::LDAP)
|
|
|| Auth::isAlternateAuth($this->fields['authtype']))) {
|
|
|
|
if (isset($this->fields["id"]) && ($this->fields["id"] > 0)) {
|
|
$authtype = Auth::getMethodsByID($this->fields["authtype"], $this->fields["auths_id"]);
|
|
|
|
if (count($authtype)) {
|
|
// Clean groups
|
|
$this->input["_groups"] = array_unique ($this->input["_groups"]);
|
|
|
|
// Delete not available groups like to LDAP
|
|
$iterator = $DB->request([
|
|
'SELECT' => [
|
|
'glpi_groups_users.id',
|
|
'glpi_groups_users.groups_id',
|
|
'glpi_groups_users.is_dynamic'
|
|
],
|
|
'FROM' => 'glpi_groups_users',
|
|
'LEFT JOIN' => [
|
|
'glpi_groups' => [
|
|
'FKEY' => [
|
|
'glpi_groups_users' => 'groups_id',
|
|
'glpi_groups' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_groups_users.users_id' => $this->fields['id']
|
|
]
|
|
]);
|
|
|
|
$groupuser = new Group_User();
|
|
while ($data = $iterator->next()) {
|
|
|
|
if (in_array($data["groups_id"], $this->input["_groups"])) {
|
|
// Delete found item in order not to add it again
|
|
unset($this->input["_groups"][array_search($data["groups_id"],
|
|
$this->input["_groups"])]);
|
|
|
|
} else if ($data['is_dynamic']) {
|
|
$groupuser->delete(['id' => $data["id"]]);
|
|
}
|
|
}
|
|
|
|
//If the user needs to be added to one group or more
|
|
if (count($this->input["_groups"]) > 0) {
|
|
foreach ($this->input["_groups"] as $group) {
|
|
$groupuser->add(['users_id' => $this->fields["id"],
|
|
'groups_id' => $group,
|
|
'is_dynamic' => 1]);
|
|
}
|
|
unset ($this->input["_groups"]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Synchronize picture (photo) of the user.
|
|
*
|
|
* @since 0.85
|
|
*
|
|
* @return string|boolean Filename to be stored in user picture field, false if no picture found
|
|
*/
|
|
function syncLdapPhoto() {
|
|
|
|
if (isset($this->fields["authtype"])
|
|
&& (($this->fields["authtype"] == Auth::LDAP)
|
|
|| ($this->fields["authtype"] == Auth::NOT_YET_AUTHENTIFIED
|
|
&& !empty($this->fields["auths_id"]))
|
|
|| Auth::isAlternateAuth($this->fields['authtype']))) {
|
|
|
|
if (isset($this->fields["id"]) && ($this->fields["id"] > 0)) {
|
|
$config_ldap = new AuthLDAP();
|
|
$ds = false;
|
|
|
|
//connect ldap server
|
|
if ($config_ldap->getFromDB($this->fields['auths_id'])) {
|
|
$ds = $config_ldap->connect();
|
|
}
|
|
|
|
if ($ds) {
|
|
//get picture fields
|
|
$picture_field = $config_ldap->fields['picture_field'];
|
|
if (empty($picture_field)) {
|
|
return false;
|
|
}
|
|
|
|
//get picture content in ldap
|
|
$info = AuthLDAP::getUserByDn($ds, $this->fields['user_dn'],
|
|
[$picture_field], false);
|
|
|
|
//getUserByDn returns an array. If the picture is empty,
|
|
//$info[$picture_field][0] is null
|
|
if (!isset($info[$picture_field][0]) || empty($info[$picture_field][0])) {
|
|
return "";
|
|
}
|
|
//prepare paths
|
|
$img = array_pop($info[$picture_field]);
|
|
$filename = uniqid($this->fields['id'].'_');
|
|
$sub = substr($filename, -2); /* 2 hex digit */
|
|
$file = GLPI_PICTURE_DIR . "/$sub/${filename}.jpg";
|
|
|
|
if (array_key_exists('picture', $this->fields)) {
|
|
$oldfile = GLPI_PICTURE_DIR . "/" . $this->fields["picture"];
|
|
} else {
|
|
$oldfile = null;
|
|
}
|
|
|
|
// update picture if not exist or changed
|
|
if (empty($this->fields["picture"])
|
|
|| !file_exists($oldfile)
|
|
|| sha1_file($oldfile) !== sha1($img)) {
|
|
if (!is_dir(GLPI_PICTURE_DIR . "/$sub")) {
|
|
mkdir(GLPI_PICTURE_DIR . "/$sub");
|
|
}
|
|
|
|
//save picture
|
|
$outjpeg = fopen($file, 'wb');
|
|
fwrite($outjpeg, $img);
|
|
fclose ($outjpeg);
|
|
|
|
//save thumbnail
|
|
$thumb = GLPI_PICTURE_DIR . "/$sub/${filename}_min.jpg";
|
|
Toolbox::resizePicture($file, $thumb);
|
|
|
|
return "$sub/${filename}.jpg";
|
|
}
|
|
return $this->fields["picture"];
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Update emails of the user.
|
|
* Uses _useremails set from UI, not _emails set from LDAP.
|
|
*
|
|
* @return void
|
|
*/
|
|
function updateUserEmails() {
|
|
// Update emails (use _useremails set from UI, not _emails set from LDAP)
|
|
|
|
$userUpdated = false;
|
|
|
|
if (isset($this->input['_useremails']) && count($this->input['_useremails'])) {
|
|
$useremail = new UserEmail();
|
|
foreach ($this->input['_useremails'] as $id => $email) {
|
|
$email = trim($email);
|
|
|
|
// existing email
|
|
if ($id > 0) {
|
|
$params = ['id' => $id];
|
|
|
|
// empty email : delete
|
|
if (strlen($email) == 0) {
|
|
$deleted = $useremail->delete($params);
|
|
$userUpdated = $userUpdated || $deleted;
|
|
|
|
} else { // Update email
|
|
$params['email'] = $email;
|
|
$params['is_default'] = $this->input['_default_email'] == $id ? 1 : 0;
|
|
|
|
$existingUserEmail = new UserEmail();
|
|
$existingUserEmail->getFromDB($id);
|
|
if ($params['email'] == $existingUserEmail->fields['email']
|
|
&& $params['is_default'] == $existingUserEmail->fields['is_default']) {
|
|
// Do not update if email has not changed
|
|
continue;
|
|
}
|
|
|
|
$updated = $useremail->update($params);
|
|
$userUpdated = $userUpdated || $updated;
|
|
}
|
|
|
|
} else { // New email
|
|
$email_input = ['email' => $email,
|
|
'users_id' => $this->fields['id']];
|
|
if (isset($this->input['_default_email'])
|
|
&& ($this->input['_default_email'] == $id)) {
|
|
$email_input['is_default'] = 1;
|
|
} else {
|
|
$email_input['is_default'] = 0;
|
|
}
|
|
$added = $useremail->add($email_input);
|
|
$userUpdated = $userUpdated || $added;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($userUpdated) {
|
|
// calling $this->update() here leads to loss in $this->input
|
|
$user = new User();
|
|
$user->update(['id' => $this->fields['id'], 'date_mod' => $_SESSION['glpi_currenttime']]);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Synchronise Dynamics emails of the user.
|
|
* Uses _emails (set from getFromLDAP), not _usermails set from UI.
|
|
*
|
|
* @return void
|
|
*/
|
|
function syncDynamicEmails() {
|
|
global $DB;
|
|
|
|
$userUpdated = false;
|
|
|
|
// input["_emails"] not set when update from user.form or preference
|
|
if (isset($this->fields["authtype"])
|
|
&& isset($this->input["_emails"])
|
|
&& (($this->fields["authtype"] == Auth::LDAP)
|
|
|| Auth::isAlternateAuth($this->fields['authtype'])
|
|
|| ($this->fields["authtype"] == Auth::MAIL))) {
|
|
|
|
if (isset($this->fields["id"]) && ($this->fields["id"] > 0)) {
|
|
$authtype = Auth::getMethodsByID($this->fields["authtype"], $this->fields["auths_id"]);
|
|
|
|
if (count($authtype)
|
|
|| $this->fields["authtype"] == Auth::EXTERNAL) {
|
|
// Clean emails
|
|
// Do a case insensitive comparison as it seems that some LDAP servers
|
|
// may return same email with different case sensitivity.
|
|
$unique_emails = [];
|
|
foreach ($this->input["_emails"] as $email) {
|
|
if (!in_array(strtolower($email), array_map('strtolower', $unique_emails))) {
|
|
$unique_emails[] = $email;
|
|
}
|
|
}
|
|
$this->input["_emails"] = $unique_emails;
|
|
|
|
// Delete not available groups like to LDAP
|
|
$iterator = $DB->request([
|
|
'SELECT' => [
|
|
'id',
|
|
'users_id',
|
|
'email',
|
|
'is_dynamic'
|
|
],
|
|
'FROM' => 'glpi_useremails',
|
|
'WHERE' => ['users_id' => $this->fields['id']]
|
|
]);
|
|
|
|
$useremail = new UserEmail();
|
|
while ($data = $iterator->next()) {
|
|
// Do a case insensitive comparison as email may be stored with a different case
|
|
$i = array_search(strtolower($data["email"]), array_map('strtolower', $this->input["_emails"]));
|
|
if ($i !== false) {
|
|
// Delete found item in order not to add it again
|
|
unset($this->input["_emails"][$i]);
|
|
} else if ($data['is_dynamic']) {
|
|
// Delete not found email
|
|
$deleted = $useremail->delete(['id' => $data["id"]]);
|
|
$userUpdated = $userUpdated || $deleted;
|
|
}
|
|
}
|
|
|
|
//If the email need to be added
|
|
if (count($this->input["_emails"]) > 0) {
|
|
foreach ($this->input["_emails"] as $email) {
|
|
$added = $useremail->add(['users_id' => $this->fields["id"],
|
|
'email' => $email,
|
|
'is_dynamic' => 1]);
|
|
$userUpdated = $userUpdated || $added;
|
|
}
|
|
unset ($this->input["_emails"]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($userUpdated) {
|
|
// calling $this->update() here leads to loss in $this->input
|
|
$user = new User();
|
|
$user->update(['id' => $this->fields['id'], 'date_mod' => $_SESSION['glpi_currenttime']]);
|
|
}
|
|
}
|
|
|
|
protected function computeFriendlyName() {
|
|
global $CFG_GLPI;
|
|
|
|
if (isset($this->fields["id"]) && ($this->fields["id"] > 0)) {
|
|
//computeFriendlyName should not add ID
|
|
$bkp_conf = $CFG_GLPI['is_ids_visible'];
|
|
$CFG_GLPI['is_ids_visible'] = 0;
|
|
$bkp_sessconf = (isset($_SESSION['glpiis_ids_visible']) ? $_SESSION["glpiis_ids_visible"] : 0);
|
|
$_SESSION["glpiis_ids_visible"] = 0;
|
|
$name = formatUserName($this->fields["id"],
|
|
$this->fields["name"],
|
|
(isset($this->fields["realname"]) ? $this->fields["realname"] : ''),
|
|
(isset($this->fields["firstname"]) ? $this->fields["firstname"] : ''));
|
|
|
|
$CFG_GLPI['is_ids_visible'] = $bkp_conf;
|
|
$_SESSION["glpiis_ids_visible"] = $bkp_sessconf;
|
|
return $name;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
|
|
/**
|
|
* Function that tries to load the user membership from LDAP
|
|
* by searching in the attributes of the User.
|
|
*
|
|
* @param resource $ldap_connection LDAP connection
|
|
* @param array $ldap_method LDAP method
|
|
* @param string $userdn Basedn of the user
|
|
* @param string $login User login
|
|
*
|
|
* @return string|boolean Basedn of the user / false if not found
|
|
*/
|
|
private function getFromLDAPGroupVirtual($ldap_connection, array $ldap_method, $userdn, $login) {
|
|
global $DB;
|
|
|
|
// Search in DB the ldap_field we need to search for in LDAP
|
|
$iterator = $DB->request([
|
|
'SELECT' => 'ldap_field',
|
|
'DISTINCT' => true,
|
|
'FROM' => 'glpi_groups',
|
|
'WHERE' => ['NOT' => ['ldap_field' => '']],
|
|
'ORDER' => 'ldap_field'
|
|
]);
|
|
$group_fields = [];
|
|
|
|
while ($data = $iterator->next()) {
|
|
$group_fields[] = Toolbox::strtolower($data["ldap_field"]);
|
|
}
|
|
if (count($group_fields)) {
|
|
//Need to sort the array because edirectory don't like it!
|
|
sort($group_fields);
|
|
|
|
// If the groups must be retrieve from the ldap user object
|
|
$sr = @ ldap_read($ldap_connection, $userdn, "objectClass=*", $group_fields);
|
|
$v = AuthLDAP::get_entries_clean($ldap_connection, $sr);
|
|
|
|
for ($i=0; $i < $v['count']; $i++) {
|
|
//Try to find is DN in present and needed: if yes, then extract only the OU from it
|
|
if ((($ldap_method["group_field"] == 'dn') || in_array('ou', $group_fields))
|
|
&& isset($v[$i]['dn'])) {
|
|
|
|
$v[$i]['ou'] = [];
|
|
for ($tmp=$v[$i]['dn']; count($tmptab = explode(',', $tmp, 2))==2; $tmp=$tmptab[1]) {
|
|
$v[$i]['ou'][] = $tmptab[1];
|
|
}
|
|
|
|
// Search in DB for group with ldap_group_dn
|
|
if (($ldap_method["group_field"] == 'dn')
|
|
&& (count($v[$i]['ou']) > 0)) {
|
|
$group_iterator = $DB->request([
|
|
'SELECT' => 'id',
|
|
'FROM' => 'glpi_groups',
|
|
'WHERE' => ['ldap_group_dn' => Toolbox::addslashes_deep($v[$i]['ou'])]
|
|
]);
|
|
|
|
while ($group = $group_iterator->next()) {
|
|
$this->fields["_groups"][] = $group['id'];
|
|
}
|
|
}
|
|
|
|
// searching with ldap_field='OU' and ldap_value is also possible
|
|
$v[$i]['ou']['count'] = count($v[$i]['ou']);
|
|
}
|
|
|
|
// For each attribute retrieve from LDAP, search in the DB
|
|
foreach ($group_fields as $field) {
|
|
if (isset($v[$i][$field])
|
|
&& isset($v[$i][$field]['count'])
|
|
&& ($v[$i][$field]['count'] > 0)) {
|
|
|
|
unset($v[$i][$field]['count']);
|
|
$lgroups = [];
|
|
foreach (Toolbox::addslashes_deep($v[$i][$field]) as $lgroup) {
|
|
$lgroups[] = [
|
|
new \QueryExpression($DB::quoteValue($lgroup).
|
|
" LIKE ".
|
|
$DB::quoteName('ldap_value'))
|
|
];
|
|
}
|
|
$group_iterator = $DB->request([
|
|
'SELECT' => 'id',
|
|
'FROM' => 'glpi_groups',
|
|
'WHERE' => [
|
|
'ldap_field' => $field,
|
|
'OR' => $lgroups
|
|
]
|
|
]);
|
|
|
|
while ($group = $group_iterator->next()) {
|
|
$this->fields["_groups"][] = $group['id'];
|
|
}
|
|
}
|
|
}
|
|
} // for each ldapresult
|
|
} // count($group_fields)
|
|
}
|
|
|
|
|
|
/**
|
|
* Function that tries to load the user membership from LDAP
|
|
* by searching in the attributes of the Groups.
|
|
*
|
|
* @param resource $ldap_connection LDAP connection
|
|
* @param array $ldap_method LDAP method
|
|
* @param string $userdn Basedn of the user
|
|
* @param string $login User login
|
|
*
|
|
* @return boolean true if search is applicable, false otherwise
|
|
*/
|
|
private function getFromLDAPGroupDiscret($ldap_connection, array $ldap_method, $userdn, $login) {
|
|
global $DB;
|
|
|
|
// No group_member_field : unable to get group
|
|
if (empty($ldap_method["group_member_field"])) {
|
|
return false;
|
|
}
|
|
|
|
if ($ldap_method["use_dn"]) {
|
|
$user_tmp = $userdn;
|
|
} else {
|
|
//Don't add $ldap_method["login_field"]."=", because sometimes it may not work (for example with posixGroup)
|
|
$user_tmp = $login;
|
|
}
|
|
|
|
$v = $this->ldap_get_user_groups($ldap_connection, $ldap_method["basedn"],
|
|
$user_tmp,
|
|
$ldap_method["group_condition"],
|
|
$ldap_method["group_member_field"],
|
|
$ldap_method["use_dn"],
|
|
$ldap_method["login_field"]);
|
|
foreach ($v as $result) {
|
|
if (isset($result[$ldap_method["group_member_field"]])
|
|
&& is_array($result[$ldap_method["group_member_field"]])
|
|
&& (count($result[$ldap_method["group_member_field"]]) > 0)) {
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => 'id',
|
|
'FROM' => 'glpi_groups',
|
|
'WHERE' => ['ldap_group_dn' => Toolbox::addslashes_deep($result[$ldap_method["group_member_field"]])]
|
|
]);
|
|
|
|
while ($group = $iterator->next()) {
|
|
$this->fields["_groups"][] = $group['id'];
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Function that tries to load the user informations from LDAP.
|
|
*
|
|
* @param resource $ldap_connection LDAP connection
|
|
* @param array $ldap_method LDAP method
|
|
* @param string $userdn Basedn of the user
|
|
* @param string $login User Login
|
|
* @param boolean $import true for import, false for update
|
|
*
|
|
* @return boolean true if found / false if not
|
|
*/
|
|
function getFromLDAP($ldap_connection, array $ldap_method, $userdn, $login, $import = true) {
|
|
global $DB, $CFG_GLPI;
|
|
|
|
// we prevent some delay...
|
|
if (empty($ldap_method["host"])) {
|
|
return false;
|
|
}
|
|
|
|
if (is_resource($ldap_connection)) {
|
|
//Set all the search fields
|
|
$this->fields['password'] = "";
|
|
|
|
$fields = AuthLDAP::getSyncFields($ldap_method);
|
|
|
|
//Hook to allow plugin to request more attributes from ldap
|
|
$fields = Plugin::doHookFunction("retrieve_more_field_from_ldap", $fields);
|
|
|
|
$fields = array_filter($fields);
|
|
$f = self::getLdapFieldNames($fields);
|
|
|
|
$sr = @ ldap_read($ldap_connection, $userdn, "objectClass=*", $f);
|
|
$v = AuthLDAP::get_entries_clean($ldap_connection, $sr);
|
|
|
|
if (!is_array($v)
|
|
|| ( count($v) == 0)
|
|
|| empty($v[0][$fields['name']][0])) {
|
|
return false;
|
|
}
|
|
|
|
//Store user's dn
|
|
$this->fields['user_dn'] = addslashes($userdn);
|
|
//Store date_sync
|
|
$this->fields['date_sync'] = $_SESSION['glpi_currenttime'];
|
|
// Empty array to ensure than syncDynamicEmails will be done
|
|
$this->fields["_emails"] = [];
|
|
// force authtype as we retrieve this user by ldap (we could have login with SSO)
|
|
$this->fields["authtype"] = Auth::LDAP;
|
|
|
|
foreach ($fields as $k => $e) {
|
|
$val = AuthLDAP::getFieldValue(
|
|
[$e => self::getLdapFieldValue($e, $v)],
|
|
$e
|
|
);
|
|
if (empty($val)) {
|
|
switch ($k) {
|
|
case "language" :
|
|
// Not set value : managed but user class
|
|
break;
|
|
|
|
case "usertitles_id" :
|
|
case "usercategories_id" :
|
|
case 'locations_id' :
|
|
case 'users_id_supervisor' :
|
|
$this->fields[$k] = 0;
|
|
break;
|
|
|
|
default :
|
|
$this->fields[$k] = "";
|
|
}
|
|
|
|
} else {
|
|
$val = Toolbox::addslashes_deep($val);
|
|
switch ($k) {
|
|
case "email1" :
|
|
case "email2" :
|
|
case "email3" :
|
|
case "email4" :
|
|
// Manage multivaluable fields
|
|
if (!empty($v[0][$e])) {
|
|
foreach ($v[0][$e] as $km => $m) {
|
|
if (!preg_match('/count/', $km)) {
|
|
$this->fields["_emails"][] = addslashes($m);
|
|
}
|
|
}
|
|
// Only get them once if duplicated
|
|
$this->fields["_emails"] = array_unique($this->fields["_emails"]);
|
|
}
|
|
break;
|
|
|
|
case "language" :
|
|
$language = Config::getLanguage($val);
|
|
if ($language != '') {
|
|
$this->fields[$k] = $language;
|
|
}
|
|
break;
|
|
|
|
case "usertitles_id" :
|
|
$this->fields[$k] = Dropdown::importExternal('UserTitle', $val);
|
|
break;
|
|
|
|
case 'locations_id' :
|
|
// use import to build the location tree
|
|
$this->fields[$k] = Dropdown::import('Location',
|
|
['completename' => $val,
|
|
'entities_id' => 0,
|
|
'is_recursive' => 1]);
|
|
break;
|
|
|
|
case "usercategories_id" :
|
|
$this->fields[$k] = Dropdown::importExternal('UserCategory', $val);
|
|
break;
|
|
|
|
case 'users_id_supervisor':
|
|
$this->fields[$k] = self::getIdByField('user_dn', $val, false);
|
|
break;
|
|
|
|
default :
|
|
$this->fields[$k] = $val;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Empty array to ensure than syncLdapGroups will be done
|
|
$this->fields["_groups"] = [];
|
|
|
|
///The groups are retrieved by looking into an ldap user object
|
|
if (($ldap_method["group_search_type"] == 0)
|
|
|| ($ldap_method["group_search_type"] == 2)) {
|
|
$this->getFromLDAPGroupVirtual($ldap_connection, $ldap_method, $userdn, $login);
|
|
}
|
|
|
|
///The groups are retrived by looking into an ldap group object
|
|
if (($ldap_method["group_search_type"] == 1)
|
|
|| ($ldap_method["group_search_type"] == 2)) {
|
|
$this->getFromLDAPGroupDiscret($ldap_connection, $ldap_method, $userdn, $login);
|
|
}
|
|
|
|
///Only process rules if working on the master database
|
|
if (!$DB->isSlave()) {
|
|
//Instanciate the affectation's rule
|
|
$rule = new RuleRightCollection();
|
|
|
|
//Process affectation rules :
|
|
//we don't care about the function's return because all
|
|
//the datas are stored in session temporary
|
|
if (isset($this->fields["_groups"])) {
|
|
$groups = $this->fields["_groups"];
|
|
} else {
|
|
$groups = [];
|
|
}
|
|
|
|
$this->fields = $rule->processAllRules($groups, Toolbox::stripslashes_deep($this->fields), [
|
|
'type' => Auth::LDAP,
|
|
'ldap_server' => $ldap_method["id"],
|
|
'connection' => $ldap_connection,
|
|
'userdn' => $userdn,
|
|
'login' => $this->fields['name'],
|
|
'mail_email' => $this->fields['_emails']
|
|
]);
|
|
|
|
$this->fields['_ruleright_process'] = true;
|
|
|
|
//If rule action is ignore import
|
|
if ($import
|
|
&& isset($this->fields["_stop_import"])) {
|
|
return false;
|
|
}
|
|
//or no rights found & do not import users with no rights
|
|
if ($import
|
|
&& !$CFG_GLPI["use_noright_users_add"]) {
|
|
$ok = false;
|
|
if (isset($this->fields["_ldap_rules"])
|
|
&& count($this->fields["_ldap_rules"])) {
|
|
if (isset($this->fields["_ldap_rules"]["rules_entities_rights"])
|
|
&& count($this->fields["_ldap_rules"]["rules_entities_rights"])) {
|
|
$ok = true;
|
|
}
|
|
if (!$ok) {
|
|
$entity_count = 0;
|
|
$right_count = 0;
|
|
if (Profile::getDefault()) {
|
|
$right_count++;
|
|
}
|
|
if (isset($this->fields["_ldap_rules"]["rules_entities"])) {
|
|
$entity_count += count($this->fields["_ldap_rules"]["rules_entities"]);
|
|
}
|
|
if (isset($this->input["_ldap_rules"]["rules_rights"])) {
|
|
$right_count += count($this->fields["_ldap_rules"]["rules_rights"]);
|
|
}
|
|
if ($entity_count && $right_count) {
|
|
$ok = true;
|
|
}
|
|
}
|
|
}
|
|
if (!$ok) {
|
|
$this->fields["_stop_import"] = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Add ldap result to data send to the hook
|
|
$this->fields['_ldap_result'] = $v;
|
|
$this->fields['_ldap_conn'] = $ldap_connection;
|
|
//Hook to retrieve more information for ldap
|
|
$this->fields = Plugin::doHookFunction("retrieve_more_data_from_ldap", $this->fields);
|
|
unset($this->fields['_ldap_result']);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
|
|
} // getFromLDAP()
|
|
|
|
|
|
/**
|
|
* Get all groups a user belongs to.
|
|
*
|
|
* @param resource $ds ldap connection
|
|
* @param string $ldap_base_dn Basedn used
|
|
* @param string $user_dn Basedn of the user
|
|
* @param string $group_condition group search condition
|
|
* @param string $group_member_field group field member in a user object
|
|
* @param boolean $use_dn search dn of user ($login_field=$user_dn) in group_member_field
|
|
* @param string $login_field user login field
|
|
*
|
|
* @return array Groups of the user located in [0][$group_member_field] in returned array
|
|
*/
|
|
function ldap_get_user_groups($ds, $ldap_base_dn, $user_dn, $group_condition,
|
|
$group_member_field, $use_dn, $login_field) {
|
|
|
|
$groups = [];
|
|
$listgroups = [];
|
|
|
|
//User dn may contain ( or ), need to espace it!
|
|
$user_dn = str_replace(["(", ")", "\,", "\+"], ["\(", "\)", "\\\,", "\\\+"],
|
|
$user_dn);
|
|
|
|
//Only retrive cn and member attributes from groups
|
|
$attrs = ['dn'];
|
|
|
|
if (!$use_dn) {
|
|
$filter = "(& $group_condition (|($group_member_field=$user_dn)
|
|
($group_member_field=$login_field=$user_dn)))";
|
|
} else {
|
|
$filter = "(& $group_condition ($group_member_field=$user_dn))";
|
|
}
|
|
|
|
//Perform the search
|
|
$filter = Toolbox::unclean_cross_side_scripting_deep($filter);
|
|
$sr = ldap_search($ds, $ldap_base_dn, $filter, $attrs);
|
|
|
|
//Get the result of the search as an array
|
|
$info = AuthLDAP::get_entries_clean($ds, $sr);
|
|
//Browse all the groups
|
|
$info_count = count($info);
|
|
for ($i = 0; $i < $info_count; $i++) {
|
|
//Get the cn of the group and add it to the list of groups
|
|
if (isset($info[$i]["dn"]) && ($info[$i]["dn"] != '')) {
|
|
$listgroups[$i] = $info[$i]["dn"];
|
|
}
|
|
}
|
|
|
|
//Create an array with the list of groups of the user
|
|
$groups[0][$group_member_field] = $listgroups;
|
|
//Return the groups of the user
|
|
return $groups;
|
|
}
|
|
|
|
|
|
/**
|
|
* Function that tries to load the user informations from IMAP.
|
|
*
|
|
* @param array $mail_method mail method description array
|
|
* @param string $name login of the user
|
|
*
|
|
* @return boolean true if method is applicable, false otherwise
|
|
*/
|
|
function getFromIMAP(array $mail_method, $name) {
|
|
global $DB;
|
|
|
|
// we prevent some delay..
|
|
if (empty($mail_method["host"])) {
|
|
return false;
|
|
}
|
|
|
|
// some defaults...
|
|
$this->fields['password'] = "";
|
|
// Empty array to ensure than syncDynamicEmails will be done
|
|
$this->fields["_emails"] = [];
|
|
$email = '';
|
|
if (strpos($name, "@")) {
|
|
$email = $name;
|
|
} else {
|
|
$email = $name . "@" . $mail_method["host"];
|
|
}
|
|
$this->fields["_emails"][] = $email;
|
|
|
|
$this->fields['name'] = $name;
|
|
//Store date_sync
|
|
$this->fields['date_sync'] = $_SESSION['glpi_currenttime'];
|
|
// force authtype as we retrieve this user by imap (we could have login with SSO)
|
|
$this->fields["authtype"] = Auth::MAIL;
|
|
|
|
if (!$DB->isSlave()) {
|
|
//Instanciate the affectation's rule
|
|
$rule = new RuleRightCollection();
|
|
|
|
//Process affectation rules :
|
|
//we don't care about the function's return because all the datas are stored in session temporary
|
|
if (isset($this->fields["_groups"])) {
|
|
$groups = $this->fields["_groups"];
|
|
} else {
|
|
$groups = [];
|
|
}
|
|
$this->fields = $rule->processAllRules($groups, Toolbox::stripslashes_deep($this->fields), [
|
|
'type' => Auth::MAIL,
|
|
'mail_server' => $mail_method["id"],
|
|
'login' => $name,
|
|
'email' => $email]
|
|
);
|
|
$this->fields['_ruleright_process'] = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Function that tries to load the user informations from the SSO server.
|
|
*
|
|
* @since 0.84
|
|
*
|
|
* @return boolean true if method is applicable, false otherwise
|
|
*/
|
|
function getFromSSO() {
|
|
global $DB, $CFG_GLPI;
|
|
|
|
$a_field = [];
|
|
foreach ($CFG_GLPI as $key=>$value) {
|
|
if (!is_array($value) && !empty($value)
|
|
&& strstr($key, "_ssofield")) {
|
|
$key = str_replace('_ssofield', '', $key);
|
|
$a_field[$key] = $value;
|
|
}
|
|
}
|
|
|
|
if (count($a_field) == 0) {
|
|
return true;
|
|
}
|
|
$this->fields['_ruleright_process'] = true;
|
|
foreach ($a_field as $field=>$value) {
|
|
if (!isset($_SERVER[$value])
|
|
|| empty($_SERVER[$value])) {
|
|
|
|
switch ($field) {
|
|
case "title" :
|
|
$this->fields['usertitles_id'] = 0;
|
|
break;
|
|
|
|
case "category" :
|
|
$this->fields['usercategories_id'] = 0;
|
|
break;
|
|
|
|
default :
|
|
$this->fields[$field] = "";
|
|
}
|
|
|
|
} else {
|
|
switch ($field) {
|
|
case "email1" :
|
|
case "email2" :
|
|
case "email3" :
|
|
case "email4" :
|
|
// Manage multivaluable fields
|
|
if (!preg_match('/count/', $_SERVER[$value])) {
|
|
$this->fields["_emails"][] = addslashes($_SERVER[$value]);
|
|
}
|
|
// Only get them once if duplicated
|
|
$this->fields["_emails"] = array_unique($this->fields["_emails"]);
|
|
break;
|
|
|
|
case "language" :
|
|
$language = Config::getLanguage($_SERVER[$value]);
|
|
if ($language != '') {
|
|
$this->fields[$field] = $language;
|
|
}
|
|
break;
|
|
|
|
case "title" :
|
|
$this->fields['usertitles_id']
|
|
= Dropdown::importExternal('UserTitle', addslashes($_SERVER[$value]));
|
|
break;
|
|
|
|
case "category" :
|
|
$this->fields['usercategories_id']
|
|
= Dropdown::importExternal('UserCategory', addslashes($_SERVER[$value]));
|
|
break;
|
|
|
|
default :
|
|
$this->fields[$field] = $_SERVER[$value];
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
///Only process rules if working on the master database
|
|
if (!$DB->isSlave()) {
|
|
//Instanciate the affectation's rule
|
|
$rule = new RuleRightCollection();
|
|
|
|
$this->fields = $rule->processAllRules([], Toolbox::stripslashes_deep($this->fields), [
|
|
'type' => Auth::EXTERNAL,
|
|
'email' => $this->fields["_emails"],
|
|
'login' => $this->fields["name"]
|
|
]);
|
|
|
|
//If rule action is ignore import
|
|
if (isset($this->fields["_stop_import"])) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Blank passwords field of a user in the DB.
|
|
* Needed for external auth users.
|
|
*
|
|
* @return void
|
|
*/
|
|
function blankPassword() {
|
|
global $DB;
|
|
|
|
if (!empty($this->fields["name"])) {
|
|
$DB->update(
|
|
$this->getTable(), [
|
|
'password' => ''
|
|
], [
|
|
'name' => $this->fields['name']
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Print a good title for user pages.
|
|
*
|
|
* @return void
|
|
*/
|
|
function title() {
|
|
global $CFG_GLPI;
|
|
|
|
$buttons = [];
|
|
$title = self::getTypeName(Session::getPluralNumber());
|
|
|
|
if (static::canCreate()) {
|
|
$buttons["user.form.php"] = __('Add user...');
|
|
$title = "";
|
|
|
|
if (Auth::useAuthExt()
|
|
&& Session::haveRight("user", self::IMPORTEXTAUTHUSERS)) {
|
|
// This requires write access because don't use entity config.
|
|
$buttons["user.form.php?new=1&ext_auth=1"] = __('... From an external source');
|
|
}
|
|
}
|
|
if (Session::haveRight("user", self::IMPORTEXTAUTHUSERS)
|
|
&& (static::canCreate() || static::canUpdate())) {
|
|
if (AuthLDAP::useAuthLdap()) {
|
|
$buttons["ldap.php"] = __('LDAP directory link');
|
|
}
|
|
}
|
|
Html::displayTitle($CFG_GLPI["root_doc"] . "/pics/users.png", self::getTypeName(Session::getPluralNumber()), $title,
|
|
$buttons);
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if current user have more right than the specified one.
|
|
*
|
|
* @param integer $ID ID of the user
|
|
*
|
|
* @return boolean
|
|
*/
|
|
function currentUserHaveMoreRightThan($ID) {
|
|
|
|
$user_prof = Profile_User::getUserProfiles($ID);
|
|
return Profile::currentUserHaveMoreRightThan($user_prof);
|
|
}
|
|
|
|
|
|
/**
|
|
* Print the user form.
|
|
*
|
|
* @param integer $ID ID of the user
|
|
* @param array $options Options
|
|
* - string target Form target
|
|
* - boolean withtemplate Template or basic item
|
|
*
|
|
* @return boolean true if user found, false otherwise
|
|
*/
|
|
function showForm($ID, array $options = []) {
|
|
global $CFG_GLPI, $DB;
|
|
|
|
// Affiche un formulaire User
|
|
if (($ID != Session::getLoginUserID()) && !self::canView()) {
|
|
return false;
|
|
}
|
|
|
|
$this->initForm($ID, $options);
|
|
|
|
$ismyself = $ID == Session::getLoginUserID();
|
|
$higherrights = $this->currentUserHaveMoreRightThan($ID);
|
|
if ($ID) {
|
|
$caneditpassword = $higherrights || ($ismyself && Session::haveRight('password_update', 1));
|
|
} else {
|
|
// can edit on creation form
|
|
$caneditpassword = true;
|
|
}
|
|
|
|
$extauth = !(($this->fields["authtype"] == Auth::DB_GLPI)
|
|
|| (($this->fields["authtype"] == Auth::NOT_YET_AUTHENTIFIED)
|
|
&& !empty($this->fields["password"])));
|
|
|
|
$formtitle = $this->getTypeName(1);
|
|
|
|
if ($ID > 0) {
|
|
$formtitle .= "<a class='pointer far fa-address-card fa-lg' target='_blank' href='".
|
|
User::getFormURLWithID($ID)."&getvcard=1' title='".__s('Download user VCard').
|
|
"'><span class='sr-only'>". __('Vcard')."</span></a>";
|
|
if (Session::canImpersonate($ID)) {
|
|
$formtitle .= '<button type="button" class="pointer btn-linkstyled btn-impersonate" name="impersonate" value="1">'
|
|
. '<i class="fas fa-user-secret fa-lg" title="' . __s('Impersonate') . '"></i> '
|
|
. '<span class="sr-only">' . __s('Impersonate') . '</span>'
|
|
. '</button>';
|
|
|
|
// "impersonate" button type is set to "button" on form display to prevent it to be used
|
|
// by default (as it is the first found in current form) when pressing "enter" key.
|
|
// When clicking it, switch to "submit" type to make it submit current user form.
|
|
$impersonate_js = <<<JAVASCRIPT
|
|
(function($) {
|
|
$('button[type="button"][name="impersonate"]').click(
|
|
function () {
|
|
$(this).attr('type', 'submit');
|
|
}
|
|
);
|
|
})(jQuery);
|
|
JAVASCRIPT;
|
|
$formtitle .= Html::scriptBlock($impersonate_js);
|
|
}
|
|
}
|
|
|
|
$options['formtitle'] = $formtitle;
|
|
$options['formoptions'] = ($options['formoptions'] ?? '') . " enctype='multipart/form-data'";
|
|
$this->showFormHeader($options);
|
|
$rand = mt_rand();
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='name'>" . __('Login') . "</label></td>";
|
|
if ($this->fields["name"] == "" ||
|
|
!empty($this->fields["password"])
|
|
|| ($this->fields["authtype"] == Auth::DB_GLPI)) {
|
|
//display login field for new records, or if this is not external auth
|
|
echo "<td><input name='name' id='name' value=\"" . $this->fields["name"] . "\"></td>";
|
|
} else {
|
|
echo "<td class='b'>" . $this->fields["name"];
|
|
echo "<input type='hidden' name='name' value=\"" . $this->fields["name"] . "\"></td>";
|
|
}
|
|
|
|
if (!empty($this->fields["name"])) {
|
|
echo "<td rowspan='7'>" . __('Picture') . "</td>";
|
|
echo "<td rowspan='7'>";
|
|
echo "<div class='user_picture_border_small' id='picture$rand'>";
|
|
echo "<img class='user_picture_small' alt=\"".__s('Picture')."\" src='".
|
|
User::getThumbnailURLForPicture($this->fields['picture'])."'>";
|
|
// echo "<img src='".self::getURLForPicture($this->fields["picture"])."' class='user_picture'/>";
|
|
echo "</div>";
|
|
$full_picture = "<div class='user_picture_border'>";
|
|
$full_picture .= "<img class='user_picture' alt=\"".__s('Picture')."\" src='".
|
|
User::getURLForPicture($this->fields['picture'])."'>";
|
|
$full_picture .= "</div>";
|
|
|
|
Html::showTooltip($full_picture, ['applyto' => "picture$rand"]);
|
|
echo Html::file(['name' => 'picture', 'display' => false, 'onlyimages' => true]);
|
|
echo "<input type='checkbox' name='_blank_picture'> ".__('Clear');
|
|
echo "</td>";
|
|
} else {
|
|
echo "<td rowspan='7'></td>";
|
|
echo "<td rowspan='7'></td>";
|
|
}
|
|
echo "</tr>";
|
|
|
|
//If it's an external auth, check if the sync_field must be displayed
|
|
if ($extauth
|
|
&& $this->fields['auths_id']
|
|
&& AuthLDAP::isSyncFieldConfigured($this->fields['auths_id'])) {
|
|
$syncrand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_sync_field$syncrand'>" . __('Synchronization field') . "</label></td><td>";
|
|
if (self::canUpdate()
|
|
&& (!$extauth || empty($ID))) {
|
|
Html::autocompletionTextField($this, "sync_field", ['rand' => $syncrand]);
|
|
} else {
|
|
if (empty($this->fields['sync_field'])) {
|
|
echo Dropdown::EMPTY_VALUE;
|
|
} else {
|
|
echo $this->fields['sync_field'];
|
|
}
|
|
}
|
|
echo "</td></tr>";
|
|
} else {
|
|
echo "<tr class='tab_bg_1'><td colspan='2'></td></tr>";
|
|
}
|
|
|
|
$surnamerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_realname$surnamerand'>" . __('Surname') . "</label></td><td>";
|
|
Html::autocompletionTextField($this, "realname", ['rand' => $surnamerand]);
|
|
echo "</td></tr>";
|
|
|
|
$firstnamerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_firstname$firstnamerand'>" . __('First name') . "</label></td><td>";
|
|
Html::autocompletionTextField($this, "firstname", ['rand' => $firstnamerand]);
|
|
echo "</td></tr>";
|
|
|
|
|
|
//sophal
|
|
if(!empty($this->fields["id"])){
|
|
displayPicklistSelected( 'Fonction' ,$this->fields["id_fonction"]);
|
|
}else{
|
|
displayPicklist('Fonction');
|
|
}
|
|
if(!empty($this->fields["id"])){
|
|
displayPicklistSelected( 'Structure' ,$this->fields["id_structure"]);
|
|
}else{
|
|
displayPicklist('Structure');
|
|
}
|
|
//sophal
|
|
|
|
|
|
//sophal
|
|
if(!empty($this->fields["id"])){
|
|
displayPicklistSelectedUser($this->fields["id_resp_eval"]);
|
|
}else{
|
|
displayPicklistUser();
|
|
}
|
|
//sophal
|
|
|
|
//do some rights verification
|
|
if (self::canUpdate()
|
|
&& (!$extauth || empty($ID))
|
|
&& $caneditpassword) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='password'>" . __('Password')."</label></td>";
|
|
echo "<td><input id='password' type='password' name='password' value='' size='20'
|
|
autocomplete='new-password' onkeyup=\"return passwordCheck();\"></td>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='password2'>" . __('Password confirmation') . "</label></td>";
|
|
echo "<td><input type='password' id='password2' name='password2' value='' size='20' autocomplete='new-password'>";
|
|
echo "</td></tr>";
|
|
|
|
if ($CFG_GLPI["use_password_security"]) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td rowspan='2'>";
|
|
echo __('Password security policy');
|
|
echo "</td>";
|
|
echo "<td rowspan='2'>";
|
|
Config::displayPasswordSecurityChecks();
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
}
|
|
|
|
} else {
|
|
echo "<tr class='tab_bg_1'><td></td><td></td></tr>";
|
|
echo "<tr class='tab_bg_1'><td></td><td></td></tr>";
|
|
}
|
|
|
|
$tz_warning = '';
|
|
$tz_available = $DB->areTimezonesAvailable($tz_warning);
|
|
if ($tz_available || Session::haveRight("config", READ)) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='timezone'>".__('Time zone')."</label></td><td>";
|
|
if ($tz_available) {
|
|
$timezones = $DB->getTimezones();
|
|
Dropdown::showFromArray(
|
|
'timezone',
|
|
$timezones, [
|
|
'value' => $this->fields["timezone"],
|
|
'display_emptychoice' => true
|
|
]
|
|
);
|
|
} else if (Session::haveRight("config", READ)) {
|
|
// Display a warning but only if user is more or less an admin
|
|
echo "<img src=\"{$CFG_GLPI['root_doc']}/pics/warning_min.png\">";
|
|
echo $tz_warning;
|
|
}
|
|
echo "</td></tr>";
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
if (!GLPI_DEMO_MODE) {
|
|
$activerand = mt_rand();
|
|
echo "<td><label for='dropdown_is_active$activerand'>".__('Active')."</label></td><td>";
|
|
Dropdown::showYesNo('is_active', $this->fields['is_active'], -1, ['rand' => $activerand]);
|
|
echo "</td>";
|
|
} else {
|
|
echo "<td colspan='2'></td>";
|
|
}
|
|
echo "<td>" . _n('Email', 'Emails', Session::getPluralNumber());
|
|
UserEmail::showAddEmailButton($this);
|
|
echo "</td><td>";
|
|
UserEmail::showForUser($this);
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
|
|
if (!GLPI_DEMO_MODE) {
|
|
$sincerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='showdate$sincerand'>".__('Valid since')."</label></td><td>";
|
|
Html::showDateTimeField("begin_date", ['value' => $this->fields["begin_date"],
|
|
'rand' => $sincerand,
|
|
'maybeempty' => true]);
|
|
echo "</td>";
|
|
|
|
$untilrand = mt_rand();
|
|
echo "<td><label for='showdate$untilrand'>".__('Valid until')."</label></td><td>";
|
|
Html::showDateTimeField("end_date", ['value' => $this->fields["end_date"],
|
|
'rand' => $untilrand,
|
|
'maybeempty' => true]);
|
|
echo "</td></tr>";
|
|
}
|
|
|
|
$phonerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='textfield_phone$phonerand'>" . Phone::getTypeName(1) . "</label></td><td>";
|
|
Html::autocompletionTextField($this, "phone", ['rand' => $phonerand]);
|
|
echo "</td>";
|
|
//Authentications information : auth method used and server used
|
|
//don't display is creation of a new user'
|
|
if (!empty($ID)) {
|
|
if (Session::haveRight(self::$rightname, self::READAUTHENT)) {
|
|
echo "<td>" . __('Authentication') . "</td><td>";
|
|
echo Auth::getMethodName($this->fields["authtype"], $this->fields["auths_id"]);
|
|
if (!empty($this->fields["date_sync"])) {
|
|
//TRANS: %s is the date of last sync
|
|
echo '<br>'.sprintf(__('Last synchronization on %s'),
|
|
Html::convDateTime($this->fields["date_sync"]));
|
|
}
|
|
if (!empty($this->fields["user_dn"])) {
|
|
//TRANS: %s is the user dn
|
|
echo '<br>'.sprintf(__('%1$s: %2$s'), __('User DN'), $this->fields["user_dn"]);
|
|
}
|
|
if ($this->fields['is_deleted_ldap']) {
|
|
echo '<br>'.__('User missing in LDAP directory');
|
|
}
|
|
|
|
echo "</td>";
|
|
} else {
|
|
echo "<td colspan='2'> </td>";
|
|
}
|
|
} else {
|
|
echo "<td colspan='2'><input type='hidden' name='authtype' value='1'></td>";
|
|
}
|
|
|
|
echo "</tr>";
|
|
|
|
$mobilerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='textfield_mobile$mobilerand'>" . __('Mobile phone') . "</label></td><td>";
|
|
Html::autocompletionTextField($this, "mobile", ['rand' => $mobilerand]);
|
|
echo "</td>";
|
|
$catrand = mt_rand();
|
|
echo "<td><label for='dropdown_usercategories_id$catrand'>" . __('Category') . "</label></td><td>";
|
|
UserCategory::dropdown(['value' => $this->fields["usercategories_id"], 'rand' => $catrand]);
|
|
echo "</td></tr>";
|
|
|
|
$phone2rand = mt_rand();
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='textfield_phone2$phone2rand'>" . __('Phone 2') . "</label></td><td>";
|
|
Html::autocompletionTextField($this, "phone2", ['rand' => $phone2rand]);
|
|
echo "</td>";
|
|
echo "<td rowspan='4' class='middle'><label for='comment'>" . __('Comments') . "</label></td>";
|
|
echo "<td class='center middle' rowspan='4'>";
|
|
echo "<textarea cols='45' rows='6' id='comment' name='comment' >".$this->fields["comment"]."</textarea>";
|
|
echo "</td></tr>";
|
|
|
|
$admnumrand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_registration_number$admnumrand'>" . __('Administrative number') . "</label></td><td>";
|
|
Html::autocompletionTextField($this, "registration_number", ['rand' => $admnumrand]);
|
|
echo "</td></tr>";
|
|
|
|
$titlerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='dropdown_usertitles_id$titlerand'>" . _x('person', 'Title') . "</label></td><td>";
|
|
UserTitle::dropdown(['value' => $this->fields["usertitles_id"], 'rand' => $titlerand]);
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
if (!empty($ID)) {
|
|
$locrand = mt_rand();
|
|
echo "<td><label for='dropdown_locations_id$locrand'>" . Location::getTypeName(1) . "</label></td><td>";
|
|
$entities = $this->getEntities();
|
|
if (count($entities) <= 0) {
|
|
$entities = -1;
|
|
}
|
|
Location::dropdown(['value' => $this->fields["locations_id"],
|
|
'rand' => $locrand,
|
|
'entity' => $entities]);
|
|
echo "</td>";
|
|
}
|
|
echo "</tr>";
|
|
|
|
if (empty($ID)) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<th colspan='2'>"._n('Authorization', 'Authorizations', 1)."</th>";
|
|
$recurrand = mt_rand();
|
|
echo "<td><label for='dropdown__is_recursive$recurrand'>" . __('Recursive') . "</label></td><td>";
|
|
Dropdown::showYesNo("_is_recursive", 0, -1, ['rand' => $recurrand]);
|
|
echo "</td></tr>";
|
|
$profilerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='dropdown__profiles_id$profilerand'>" . Profile::getTypeName(1) . "</label></td><td>";
|
|
Profile::dropdownUnder(['name' => '_profiles_id',
|
|
'rand' => $profilerand,
|
|
'value' => Profile::getDefault()]);
|
|
|
|
$entrand = mt_rand();
|
|
echo "</td><td><label for='dropdown__entities_id$entrand'>" . Entity::getTypeName(1) . "</label></td><td>";
|
|
Entity::dropdown(['name' => '_entities_id',
|
|
'display_emptychoice' => false,
|
|
'rand' => $entrand,
|
|
'entity' => $_SESSION['glpiactiveentities']]);
|
|
echo "</td></tr>";
|
|
} else {
|
|
if ($higherrights || $ismyself) {
|
|
$profilerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='dropdown_profiles_id$profilerand'>" . __('Default profile') . "</label></td><td>";
|
|
|
|
$options = Dropdown::getDropdownArrayNames('glpi_profiles',
|
|
Profile_User::getUserProfiles($this->fields['id']));
|
|
|
|
Dropdown::showFromArray("profiles_id", $options,
|
|
['value' => $this->fields["profiles_id"],
|
|
'rand' => $profilerand,
|
|
'display_emptychoice' => true]);
|
|
}
|
|
if ($higherrights) {
|
|
$entrand = mt_rand();
|
|
echo "</td><td><label for='dropdown_entities_id$entrand'>" . __('Default entity') . "</label></td><td>";
|
|
$entities = $this->getEntities();
|
|
Entity::dropdown(['value' => $this->fields["entities_id"],
|
|
'rand' => $entrand,
|
|
'entity' => $entities]);
|
|
echo "</td></tr>";
|
|
|
|
$grouprand = mt_rand();
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='dropdown_profiles_id$grouprand'>" . __('Default group') . "</label></td><td>";
|
|
|
|
$options = [];
|
|
foreach (Group_User::getUserGroups($this->fields['id']) as $group) {
|
|
$options[$group['id']] = $group['completename'];
|
|
}
|
|
|
|
Dropdown::showFromArray("groups_id", $options,
|
|
['value' => $this->fields["groups_id"],
|
|
'rand' => $grouprand,
|
|
'display_emptychoice' => true]);
|
|
|
|
echo "</td>";
|
|
$userrand = mt_rand();
|
|
echo "<td><label for='dropdown_users_id_supervisor_$userrand'>" . __('Responsible') . "</label></td><td>";
|
|
|
|
User::dropdown(['name' => 'users_id_supervisor',
|
|
'value' => $this->fields["users_id_supervisor"],
|
|
'rand' => $userrand,
|
|
'entity' => $_SESSION["glpiactive_entity"],
|
|
'right' => 'all']);
|
|
echo "</td></tr>";
|
|
}
|
|
|
|
if ($this->can($ID, UPDATE)) {
|
|
echo "<tr class='tab_bg_1'><th colspan='4'>". __('Remote access keys') ."</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>";
|
|
echo __("Personal token");
|
|
echo "</td><td colspan='2'>";
|
|
|
|
if (!empty($this->fields["personal_token"])) {
|
|
echo "<div class='copy_to_clipboard_wrapper'>";
|
|
echo Html::input('_personal_token', [
|
|
'value' => $this->fields["personal_token"],
|
|
'style' => 'width:90%'
|
|
]);
|
|
echo "</div>";
|
|
echo "(".sprintf(__('generated on %s'),
|
|
Html::convDateTime($this->fields["personal_token_date"])).")";
|
|
}
|
|
echo "</td><td>";
|
|
Html::showCheckbox(['name' => '_reset_personal_token',
|
|
'title' => __('Regenerate')]);
|
|
echo " ".__('Regenerate');
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>";
|
|
echo __("API token");
|
|
echo "</td><td colspan='2'>";
|
|
if (!empty($this->fields["api_token"])) {
|
|
echo "<div class='copy_to_clipboard_wrapper'>";
|
|
echo Html::input('_api_token', [
|
|
'value' => $this->fields["api_token"],
|
|
'style' => 'width:90%'
|
|
]);
|
|
echo "</div>";
|
|
echo "(".sprintf(__('generated on %s'),
|
|
Html::convDateTime($this->fields["api_token_date"])).")";
|
|
}
|
|
echo "</td><td>";
|
|
Html::showCheckbox(['name' => '_reset_api_token',
|
|
'title' => __('Regenerate')]);
|
|
echo " ".__('Regenerate');
|
|
echo "</td></tr>";
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td colspan='2' class='center'>";
|
|
if ($this->fields["last_login"]) {
|
|
printf(__('Last login on %s'), Html::convDateTime($this->fields["last_login"]));
|
|
}
|
|
echo "</td><td colspan='2'class='center'>";
|
|
|
|
echo "</td></tr>";
|
|
}
|
|
|
|
$this->showFormButtons($options);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/** Print the user personnal information for check.
|
|
*
|
|
* @param integer $userid ID of the user
|
|
*
|
|
* @return void|boolean false if user is not the current user, otherwise print form
|
|
*
|
|
* @since 0.84
|
|
*/
|
|
static function showPersonalInformation($userid) {
|
|
global $CFG_GLPI;
|
|
|
|
$user = new self();
|
|
if (!$user->can($userid, READ)
|
|
&& ($userid != Session::getLoginUserID())) {
|
|
return false;
|
|
}
|
|
echo "<table class='tab_glpi left' width='100%'>";
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td class='b' width='20%'>";
|
|
echo __('Name');
|
|
echo "</td><td width='30%'>";
|
|
echo getUserName($userid);
|
|
echo "</td>";
|
|
echo "<td class='b' width='20%'>";
|
|
echo Phone::getTypeName(1);
|
|
echo "</td><td width='30%'>";
|
|
echo $user->getField('phone');
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td class='b'>";
|
|
echo __('Phone 2');
|
|
echo "</td><td>";
|
|
echo $user->getField('phone2');
|
|
echo "</td>";
|
|
echo "<td class='b'>";
|
|
echo __('Mobile phone');
|
|
echo "</td><td>";
|
|
echo $user->getField('mobile');
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td class='b'>";
|
|
echo _n('Email', 'Emails', 1);
|
|
echo "</td><td>";
|
|
echo $user->getDefaultEmail();
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td class='b'>";
|
|
echo Location::getTypeName(1);
|
|
echo "</td><td>";
|
|
echo Dropdown::getDropdownName('glpi_locations', $user->getField('locations_id'));
|
|
echo "</td>";
|
|
echo "<td colspan='2' class='center'>";
|
|
if ($userid == Session::getLoginUserID()) {
|
|
echo "<a href='".$CFG_GLPI['root_doc']."/front/preference.php' class='vsubmit'>".
|
|
__('Edit')."</a>";
|
|
} else {
|
|
echo " ";
|
|
}
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
echo "</table>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Print the user preference form.
|
|
*
|
|
* @param string $target Form target
|
|
* @param integer $ID ID of the user
|
|
*
|
|
* @return boolean true if user found, false otherwise
|
|
*/
|
|
function showMyForm($target, $ID) {
|
|
global $CFG_GLPI, $DB;
|
|
|
|
// Affiche un formulaire User
|
|
if (($ID != Session::getLoginUserID())
|
|
&& !$this->currentUserHaveMoreRightThan($ID)) {
|
|
return false;
|
|
}
|
|
if ($this->getFromDB($ID)) {
|
|
$rand = mt_rand();
|
|
$authtype = $this->getAuthMethodsByID();
|
|
|
|
$extauth = !(($this->fields["authtype"] == Auth::DB_GLPI)
|
|
|| (($this->fields["authtype"] == Auth::NOT_YET_AUTHENTIFIED)
|
|
&& !empty($this->fields["password"])));
|
|
|
|
// No autocopletion :
|
|
$save_autocompletion = $CFG_GLPI["use_ajax_autocompletion"];
|
|
$CFG_GLPI["use_ajax_autocompletion"] = false;
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' name='user_manager' enctype='multipart/form-data' action='".$target."' autocomplete='off'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr><th colspan='4'>".sprintf(__('%1$s: %2$s'), __('Login'), $this->fields["name"]);
|
|
echo "<input type='hidden' name='name' value='" . $this->fields["name"] . "'>";
|
|
echo "<input type='hidden' name='id' value='" . $this->fields["id"] . "'>";
|
|
echo "</th></tr>";
|
|
|
|
$surnamerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_realname$surnamerand'>" . __('Surname') . "</label></td><td>";
|
|
|
|
if ($extauth
|
|
&& isset($authtype['realname_field'])
|
|
&& !empty($authtype['realname_field'])) {
|
|
|
|
echo $this->fields["realname"];
|
|
} else {
|
|
Html::autocompletionTextField($this, "realname", ['rand' => $surnamerand]);
|
|
}
|
|
echo "</td>";
|
|
|
|
if (!empty($this->fields["name"])) {
|
|
echo "<td rowspan='7'>" . __('Picture') . "</td>";
|
|
echo "<td rowspan='7'>";
|
|
echo "<div class='user_picture_border_small' id='picture$rand'>";
|
|
echo "<img class='user_picture_small' alt=\"".__s('Picture')."\" src='".
|
|
User::getThumbnailURLForPicture($this->fields['picture'])."'>";
|
|
echo "</div>";
|
|
$full_picture = "<div class='user_picture_border'>";
|
|
$full_picture .= "<img class='user_picture' alt=\"".__s('Picture')."\" src='".
|
|
User::getURLForPicture($this->fields['picture'])."'>";
|
|
$full_picture .= "</div>";
|
|
|
|
Html::showTooltip($full_picture, ['applyto' => "picture$rand"]);
|
|
echo Html::file(['name' => 'picture', 'display' => false, 'onlyimages' => true]);
|
|
|
|
echo " ";
|
|
Html::showCheckbox(['name' => '_blank_picture', 'title' => __('Clear')]);
|
|
echo " ".__('Clear');
|
|
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
}
|
|
|
|
$firstnamerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_firstname$firstnamerand'>" . __('First name') . "</label></td><td>";
|
|
if ($extauth
|
|
&& isset($authtype['firstname_field'])
|
|
&& !empty($authtype['firstname_field'])) {
|
|
|
|
echo $this->fields["firstname"];
|
|
} else {
|
|
Html::autocompletionTextField($this, "firstname", ['rand' => $firstnamerand]);
|
|
}
|
|
echo "</td></tr>";
|
|
|
|
if ($extauth
|
|
&& $this->fields['auths_id']
|
|
&& AuthLDAP::isSyncFieldConfigured($this->fields['auths_id'])) {
|
|
echo "<tr class='tab_bg_1'><td>" . __('Synchronization field') . "</td><td>";
|
|
if (empty($this->fields['sync_field'])) {
|
|
echo Dropdown::EMPTY_VALUE;
|
|
} else {
|
|
echo $this->fields['sync_field'];
|
|
}
|
|
echo "</td></tr>";
|
|
} else {
|
|
echo "<tr class='tab_bg_1'><td colspan='2'></td></tr>";
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
|
|
if (!GLPI_DEMO_MODE) {
|
|
$langrand = mt_rand();
|
|
echo "<td><label for='dropdown_language$langrand'>" . __('Language') . "</label></td><td>";
|
|
// Language is stored as null in DB if value is same as the global config.
|
|
$language = $this->fields["language"];
|
|
if (null === $this->fields["language"]) {
|
|
$language = $CFG_GLPI['language'];
|
|
}
|
|
Dropdown::showLanguages(
|
|
"language",
|
|
[
|
|
'rand' => $langrand,
|
|
'value' => $language,
|
|
]
|
|
);
|
|
echo "</td>";
|
|
} else {
|
|
echo "<td colspan='2'> </td>";
|
|
}
|
|
echo "</tr>";
|
|
|
|
//do some rights verification
|
|
if (!$extauth
|
|
&& Session::haveRight("password_update", "1")) {
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='password'>" . __('Password') . "</label></td>";
|
|
echo "<td><input id='password' type='password' name='password' value='' size='30' autocomplete='new-password' onkeyup=\"return passwordCheck();\">";
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='password2'>" . __('Password confirmation') . "</label></td>";
|
|
echo "<td><input type='password' name='password2' id='password2' value='' size='30' autocomplete='new-password'>";
|
|
echo "</td></tr>";
|
|
|
|
if ($CFG_GLPI["use_password_security"]) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td rowspan='2'>";
|
|
echo __('Password security policy');
|
|
echo "</td>";
|
|
echo "<td rowspan='2'>";
|
|
Config::displayPasswordSecurityChecks();
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
}
|
|
} else {
|
|
echo "<tr class='tab_bg_1'><td colspan='2'></td></tr>";
|
|
echo "<tr class='tab_bg_1'><td colspan='2'></td></tr>";
|
|
echo "<tr class='tab_bg_1'><td colspan='2'></td></tr>";
|
|
}
|
|
|
|
$tz_warning = '';
|
|
$tz_available = $DB->areTimezonesAvailable($tz_warning);
|
|
if ($tz_available || Session::haveRight("config", READ)) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td><label for='timezone'>".__('Time zone')."</label></td><td>";
|
|
if ($tz_available) {
|
|
$timezones = $DB->getTimezones();
|
|
Dropdown::showFromArray(
|
|
'timezone',
|
|
$timezones, [
|
|
'value' => $this->fields["timezone"],
|
|
'display_emptychoice' => true
|
|
]
|
|
);
|
|
} else if (Session::haveRight("config", READ)) {
|
|
// Display a warning but only if user is more or less an admin
|
|
echo "<img src=\"{$CFG_GLPI['root_doc']}/pics/warning_min.png\">";
|
|
echo $tz_warning;
|
|
}
|
|
echo "</td>";
|
|
if ($extauth
|
|
|| !Session::haveRight("password_update", "1")) {
|
|
echo "<td colspan='2'></td>";
|
|
}
|
|
echo "</tr>";
|
|
}
|
|
|
|
$phonerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_phone$phonerand'>" . Phone::getTypeName(1) . "</label></td><td>";
|
|
|
|
if ($extauth
|
|
&& isset($authtype['phone_field']) && !empty($authtype['phone_field'])) {
|
|
echo $this->fields["phone"];
|
|
} else {
|
|
Html::autocompletionTextField($this, "phone", ['rand' => $phonerand]);
|
|
}
|
|
echo "</td>";
|
|
echo "<td class='top'>" . _n('Email', 'Emails', Session::getPluralNumber());
|
|
UserEmail::showAddEmailButton($this);
|
|
echo "</td><td>";
|
|
UserEmail::showForUser($this);
|
|
echo "</td>";
|
|
echo "</tr>";
|
|
|
|
$mobilerand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_mobile$mobilerand'>" . __('Mobile phone') . "</label></td><td>";
|
|
|
|
if ($extauth
|
|
&& isset($authtype['mobile_field']) && !empty($authtype['mobile_field'])) {
|
|
echo $this->fields["mobile"];
|
|
} else {
|
|
Html::autocompletionTextField($this, "mobile", ['rand' => $mobilerand]);
|
|
}
|
|
echo "</td>";
|
|
|
|
if (count($_SESSION['glpiprofiles']) >1) {
|
|
$profilerand = mt_rand();
|
|
echo "<td><label for='dropdown_profiles_id$profilerand'>" . __('Default profile') . "</label></td><td>";
|
|
|
|
$options = Dropdown::getDropdownArrayNames('glpi_profiles',
|
|
Profile_User::getUserProfiles($this->fields['id']));
|
|
Dropdown::showFromArray("profiles_id", $options,
|
|
['value' => $this->fields["profiles_id"],
|
|
'rand' => $profilerand,
|
|
'display_emptychoice' => true]);
|
|
echo "</td>";
|
|
|
|
} else {
|
|
echo "<td colspan='2'> </td>";
|
|
}
|
|
echo "</tr>";
|
|
|
|
$phone2rand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_phone2$phone2rand'>" . __('Phone 2') . "</label></td><td>";
|
|
|
|
if ($extauth
|
|
&& isset($authtype['phone2_field']) && !empty($authtype['phone2_field'])) {
|
|
echo $this->fields["phone2"];
|
|
} else {
|
|
Html::autocompletionTextField($this, "phone2", ['rand' => $phone2rand]);
|
|
}
|
|
echo "</td>";
|
|
|
|
$entities = $this->getEntities();
|
|
if (!GLPI_DEMO_MODE
|
|
&& (count($_SESSION['glpiactiveentities']) > 1)) {
|
|
$entrand = mt_rand();
|
|
echo "<td><label for='dropdown_entities_id$entrand'>" . __('Default entity') . "</td><td>";
|
|
Entity::dropdown(['value' => $this->fields['entities_id'],
|
|
'rand' => $entrand,
|
|
'entity' => $entities]);
|
|
} else {
|
|
echo "<td colspan='2'> ";
|
|
}
|
|
echo "</td></tr>";
|
|
|
|
$admnumrand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='textfield_registration_number$admnumrand'>" . __('Administrative number') . "</label></td><td>";
|
|
if ($extauth
|
|
&& isset($authtype['registration_number_field']) && !empty($authtype['registration_number_field'])) {
|
|
echo $this->fields["registration_number"];
|
|
} else {
|
|
Html::autocompletionTextField($this, "registration_number", ['rand' => $admnumrand]);
|
|
}
|
|
echo "</td><td colspan='2'></td></tr>";
|
|
|
|
$locrand = mt_rand();
|
|
echo "<tr class='tab_bg_1'><td><label for='dropdown_locations_id$locrand'>" . Location::getTypeName(1) . "</label></td><td>";
|
|
Location::dropdown(['value' => $this->fields['locations_id'],
|
|
'rand' => $locrand,
|
|
'entity' => $entities]);
|
|
|
|
if (Config::canUpdate()) {
|
|
$moderand = mt_rand();
|
|
echo "<td><label for='dropdown_use_mode$moderand'>" . __('Use GLPI in mode') . "</label></td><td>";
|
|
$modes = [
|
|
Session::NORMAL_MODE => __('Normal'),
|
|
Session::DEBUG_MODE => __('Debug'),
|
|
];
|
|
Dropdown::showFromArray('use_mode', $modes, ['value' => $this->fields["use_mode"], 'rand' => $moderand]);
|
|
} else {
|
|
echo "<td colspan='2'> ";
|
|
}
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><th colspan='4'>". __('Remote access keys') ."</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>";
|
|
echo __("Personal token");
|
|
echo "</td><td colspan='2'>";
|
|
|
|
if (!empty($this->fields["personal_token"])) {
|
|
echo "<div class='copy_to_clipboard_wrapper'>";
|
|
echo Html::input('_personal_token', [
|
|
'value' => $this->fields["personal_token"],
|
|
'style' => 'width:90%'
|
|
]);
|
|
echo "</div>";
|
|
echo "(".sprintf(__('generated on %s'),
|
|
Html::convDateTime($this->fields["personal_token_date"])).")";
|
|
}
|
|
echo "</td><td>";
|
|
Html::showCheckbox(['name' => '_reset_personal_token',
|
|
'title' => __('Regenerate')]);
|
|
echo " ".__('Regenerate');
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>";
|
|
echo __("API token");
|
|
echo "</td><td colspan='2'>";
|
|
if (!empty($this->fields["api_token"])) {
|
|
echo "<div class='copy_to_clipboard_wrapper'>";
|
|
echo Html::input('_api_token', [
|
|
'value' => $this->fields["api_token"],
|
|
'style' => 'width:90%'
|
|
]);
|
|
echo "</div>";
|
|
echo "(".sprintf(__('generated on %s'),
|
|
Html::convDateTime($this->fields["api_token_date"])).")";
|
|
}
|
|
echo "</td><td>";
|
|
Html::showCheckbox(['name' => '_reset_api_token',
|
|
'title' => __('Regenerate')]);
|
|
echo " ".__('Regenerate');
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr><td class='tab_bg_2 center' colspan='4'>";
|
|
echo "<input type='submit' name='update' value=\""._sx('button', 'Save')."\" class='submit'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
$CFG_GLPI["use_ajax_autocompletion"] = $save_autocompletion;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all the authentication method parameters for the current user.
|
|
*
|
|
* @return array
|
|
*/
|
|
function getAuthMethodsByID() {
|
|
return Auth::getMethodsByID($this->fields["authtype"], $this->fields["auths_id"]);
|
|
}
|
|
|
|
|
|
function pre_updateInDB() {
|
|
global $DB;
|
|
|
|
if (($key = array_search('name', $this->updates)) !== false) {
|
|
/// Check if user does not exists
|
|
$iterator = $DB->request([
|
|
'FROM' => $this->getTable(),
|
|
'WHERE' => [
|
|
'name' => $this->input['name'],
|
|
'id' => ['<>', $this->input['id']]
|
|
]
|
|
]);
|
|
|
|
if (count($iterator)) {
|
|
//To display a message
|
|
$this->fields['name'] = $this->oldvalues['name'];
|
|
unset($this->updates[$key]);
|
|
unset($this->oldvalues['name']);
|
|
Session::addMessageAfterRedirect(__('Unable to update login. A user already exists.'),
|
|
false, ERROR);
|
|
}
|
|
|
|
if (!Auth::isValidLogin(stripslashes($this->input['name']))) {
|
|
$this->fields['name'] = $this->oldvalues['name'];
|
|
unset($this->updates[$key]);
|
|
unset($this->oldvalues['name']);
|
|
Session::addMessageAfterRedirect(__('The login is not valid. Unable to update login.'),
|
|
false, ERROR);
|
|
}
|
|
|
|
}
|
|
|
|
// ## Security system except for login update:
|
|
//
|
|
// An **external** (ldap, mail) user without User::UPDATE right
|
|
// should not be able to update its own fields
|
|
// (for example, fields concerned by ldap synchronisation)
|
|
// except on login action (which triggers synchronisation).
|
|
if (Session::getLoginUserID() === (int)$this->input['id']
|
|
&& !Session::haveRight("user", UPDATE)
|
|
&& !strpos($_SERVER['PHP_SELF'], "/front/login.php")
|
|
&& isset($this->fields["authtype"])) {
|
|
|
|
// extauth ldap case
|
|
if ($_SESSION["glpiextauth"]
|
|
&& ($this->fields["authtype"] == Auth::LDAP
|
|
|| Auth::isAlternateAuth($this->fields["authtype"]))) {
|
|
|
|
$authtype = Auth::getMethodsByID($this->fields["authtype"],
|
|
$this->fields["auths_id"]);
|
|
if (count($authtype)) {
|
|
$fields = AuthLDAP::getSyncFields($authtype);
|
|
foreach ($fields as $key => $val) {
|
|
if (!empty($val)
|
|
&& (($key2 = array_search($key, $this->updates)) !== false)) {
|
|
|
|
unset ($this->updates[$key2]);
|
|
unset($this->oldvalues[$key]);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (($key = array_search("is_active", $this->updates)) !== false) {
|
|
unset ($this->updates[$key]);
|
|
unset($this->oldvalues['is_active']);
|
|
}
|
|
|
|
if (($key = array_search("comment", $this->updates)) !== false) {
|
|
unset ($this->updates[$key]);
|
|
unset($this->oldvalues['comment']);
|
|
}
|
|
}
|
|
}
|
|
|
|
function getSpecificMassiveActions($checkitem = null) {
|
|
|
|
$isadmin = static::canUpdate();
|
|
$actions = parent::getSpecificMassiveActions($checkitem);
|
|
if ($isadmin) {
|
|
$actions['Group_User'.MassiveAction::CLASS_ACTION_SEPARATOR.'add']
|
|
= "<i class='ma-icon fas fa-users'></i>".
|
|
__('Associate to a group');
|
|
$actions['Group_User'.MassiveAction::CLASS_ACTION_SEPARATOR.'remove']
|
|
= __('Dissociate from a group');
|
|
$actions['Profile_User'.MassiveAction::CLASS_ACTION_SEPARATOR.'add']
|
|
= "<i class='ma-icon fas fa-user-shield'></i>".
|
|
__('Associate to a profile');
|
|
$actions['Profile_User'.MassiveAction::CLASS_ACTION_SEPARATOR.'remove']
|
|
= __('Dissociate from a profile');
|
|
$actions['Group_User'.MassiveAction::CLASS_ACTION_SEPARATOR.'change_group_user']
|
|
= "<i class='ma-icon fas fa-users-cog'></i>".
|
|
__("Move to group");
|
|
}
|
|
|
|
if (Session::haveRight(self::$rightname, self::UPDATEAUTHENT)) {
|
|
$prefix = __CLASS__.MassiveAction::CLASS_ACTION_SEPARATOR;
|
|
$actions[$prefix.'change_authtype'] = "<i class='ma-icon fas fa-user-cog'></i>".
|
|
_x('button', 'Change the authentication method');
|
|
$actions[$prefix.'force_user_ldap_update'] = "<i class='ma-icon fas fa-sync'></i>".
|
|
__('Force synchronization');
|
|
}
|
|
return $actions;
|
|
}
|
|
|
|
static function showMassiveActionsSubForm(MassiveAction $ma) {
|
|
global $CFG_GLPI;
|
|
|
|
switch ($ma->getAction()) {
|
|
case 'change_authtype' :
|
|
$rand = Auth::dropdown(['name' => 'authtype']);
|
|
$paramsmassaction = ['authtype' => '__VALUE__'];
|
|
Ajax::updateItemOnSelectEvent("dropdown_authtype$rand", "show_massiveaction_field",
|
|
$CFG_GLPI["root_doc"].
|
|
"/ajax/dropdownMassiveActionAuthMethods.php",
|
|
$paramsmassaction);
|
|
echo "<span id='show_massiveaction_field'><br><br>";
|
|
echo Html::submit(_x('button', 'Post'), ['name' => 'massiveaction'])."</span>";
|
|
return true;
|
|
}
|
|
return parent::showMassiveActionsSubForm($ma);
|
|
}
|
|
|
|
static function processMassiveActionsForOneItemtype(MassiveAction $ma, CommonDBTM $item,
|
|
array $ids) {
|
|
|
|
switch ($ma->getAction()) {
|
|
case 'force_user_ldap_update' :
|
|
foreach ($ids as $id) {
|
|
if ($item->can($id, UPDATE)) {
|
|
if (($item->fields["authtype"] == Auth::LDAP)
|
|
|| ($item->fields["authtype"] == Auth::EXTERNAL)) {
|
|
if (AuthLDAP::forceOneUserSynchronization($item, false)) {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_OK);
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
|
|
}
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
|
|
}
|
|
} else {
|
|
$ma->itemDone($item->getType(), $id, MassiveAction::ACTION_NORIGHT);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
|
|
}
|
|
}
|
|
return;
|
|
|
|
case 'change_authtype' :
|
|
$input = $ma->getInput();
|
|
if (!isset($input["authtype"])
|
|
|| !isset($input["auths_id"])) {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_ON_ACTION));
|
|
return;
|
|
}
|
|
if (Session::haveRight(self::$rightname, self::UPDATEAUTHENT)) {
|
|
if (User::changeAuthMethod($ids, $input["authtype"], $input["auths_id"])) {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_OK);
|
|
} else {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_KO);
|
|
}
|
|
} else {
|
|
$ma->itemDone($item->getType(), $ids, MassiveAction::ACTION_NORIGHT);
|
|
$ma->addMessage($item->getErrorMessage(ERROR_RIGHT));
|
|
}
|
|
return;
|
|
}
|
|
parent::processMassiveActionsForOneItemtype($ma, $item, $ids);
|
|
}
|
|
|
|
|
|
function rawSearchOptions() {
|
|
// forcegroup by on name set force group by for all items
|
|
$tab = [];
|
|
|
|
$tab[] = [
|
|
'id' => 'common',
|
|
'name' => __('Characteristics')
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '1',
|
|
'table' => $this->getTable(),
|
|
'field' => 'name',
|
|
'name' => __('Login'),
|
|
'datatype' => 'itemlink',
|
|
'forcegroupby' => true,
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '2',
|
|
'table' => $this->getTable(),
|
|
'field' => 'id',
|
|
'name' => __('ID'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'number'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '34',
|
|
'table' => $this->getTable(),
|
|
'field' => 'realname',
|
|
'name' => __('Last name'),
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '9',
|
|
'table' => $this->getTable(),
|
|
'field' => 'firstname',
|
|
'name' => __('First name'),
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '5',
|
|
'table' => 'glpi_useremails',
|
|
'field' => 'email',
|
|
'name' => _n('Email', 'Emails', Session::getPluralNumber()),
|
|
'datatype' => 'email',
|
|
'joinparams' => [
|
|
'jointype' => 'child'
|
|
],
|
|
'forcegroupby' => true,
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '150',
|
|
'table' => $this->getTable(),
|
|
'field' => 'picture',
|
|
'name' => __('Picture'),
|
|
'datatype' => 'specific',
|
|
'nosearch' => true,
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '28',
|
|
'table' => $this->getTable(),
|
|
'field' => 'sync_field',
|
|
'name' => __('Synchronization field'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab = array_merge($tab, Location::rawSearchOptionsToAdd());
|
|
|
|
$tab[] = [
|
|
'id' => '8',
|
|
'table' => $this->getTable(),
|
|
'field' => 'is_active',
|
|
'name' => __('Active'),
|
|
'datatype' => 'bool'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '6',
|
|
'table' => $this->getTable(),
|
|
'field' => 'phone',
|
|
'name' => Phone::getTypeName(1),
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '10',
|
|
'table' => $this->getTable(),
|
|
'field' => 'phone2',
|
|
'name' => __('Phone 2'),
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '11',
|
|
'table' => $this->getTable(),
|
|
'field' => 'mobile',
|
|
'name' => __('Mobile phone'),
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '13',
|
|
'table' => 'glpi_groups',
|
|
'field' => 'completename',
|
|
'name' => Group::getTypeName(Session::getPluralNumber()),
|
|
'forcegroupby' => true,
|
|
'datatype' => 'itemlink',
|
|
'massiveaction' => false,
|
|
'joinparams' => [
|
|
'beforejoin' => [
|
|
'table' => 'glpi_groups_users',
|
|
'joinparams' => [
|
|
'jointype' => 'child'
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '14',
|
|
'table' => $this->getTable(),
|
|
'field' => 'last_login',
|
|
'name' => __('Last login'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '15',
|
|
'table' => $this->getTable(),
|
|
'field' => 'authtype',
|
|
'name' => __('Authentication'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'specific',
|
|
'searchtype' => 'equals',
|
|
'additionalfields' => [
|
|
'0' => 'auths_id'
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '30',
|
|
'table' => 'glpi_authldaps',
|
|
'field' => 'name',
|
|
'linkfield' => 'auths_id',
|
|
'name' => __('LDAP directory for authentication'),
|
|
'massiveaction' => false,
|
|
'joinparams' => [
|
|
'condition' => 'AND REFTABLE.`authtype` = ' . Auth::LDAP
|
|
],
|
|
'datatype' => 'dropdown'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '31',
|
|
'table' => 'glpi_authmails',
|
|
'field' => 'name',
|
|
'linkfield' => 'auths_id',
|
|
'name' => __('Email server for authentication'),
|
|
'massiveaction' => false,
|
|
'joinparams' => [
|
|
'condition' => 'AND REFTABLE.`authtype` = ' . Auth::MAIL
|
|
],
|
|
'datatype' => 'dropdown'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '16',
|
|
'table' => $this->getTable(),
|
|
'field' => 'comment',
|
|
'name' => __('Comments'),
|
|
'datatype' => 'text'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '17',
|
|
'table' => $this->getTable(),
|
|
'field' => 'language',
|
|
'name' => __('Language'),
|
|
'datatype' => 'language',
|
|
'display_emptychoice' => true,
|
|
'emptylabel' => 'Default value'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '19',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_mod',
|
|
'name' => __('Last update'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '121',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_creation',
|
|
'name' => __('Creation date'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '20',
|
|
'table' => 'glpi_profiles',
|
|
'field' => 'name',
|
|
'name' => sprintf(__('%1$s (%2$s)'), Profile::getTypeName(Session::getPluralNumber()),
|
|
Entity::getTypeName(1)),
|
|
'forcegroupby' => true,
|
|
'massiveaction' => false,
|
|
'datatype' => 'dropdown',
|
|
'joinparams' => [
|
|
'beforejoin' => [
|
|
'table' => 'glpi_profiles_users',
|
|
'joinparams' => [
|
|
'jointype' => 'child'
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '21',
|
|
'table' => $this->getTable(),
|
|
'field' => 'user_dn',
|
|
'name' => __('User DN'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'text'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '22',
|
|
'table' => $this->getTable(),
|
|
'field' => 'registration_number',
|
|
'name' => __('Administrative number'),
|
|
'datatype' => 'string',
|
|
'autocomplete' => true,
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '23',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_sync',
|
|
'datatype' => 'datetime',
|
|
'name' => __('Last synchronization'),
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '24',
|
|
'table' => $this->getTable(),
|
|
'field' => 'is_deleted_ldap',
|
|
'name' => __('Deleted user in LDAP directory'),
|
|
'datatype' => 'bool',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '80',
|
|
'table' => 'glpi_entities',
|
|
'linkfield' => 'entities_id',
|
|
'field' => 'completename',
|
|
'name' => sprintf(__('%1$s (%2$s)'), Entity::getTypeName(Session::getPluralNumber()),
|
|
Profile::getTypeName(1)),
|
|
'forcegroupby' => true,
|
|
'datatype' => 'dropdown',
|
|
'massiveaction' => false,
|
|
'joinparams' => [
|
|
'beforejoin' => [
|
|
'table' => 'glpi_profiles_users',
|
|
'joinparams' => [
|
|
'jointype' => 'child'
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '81',
|
|
'table' => 'glpi_usertitles',
|
|
'field' => 'name',
|
|
'name' => __('Title'),
|
|
'datatype' => 'dropdown'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '82',
|
|
'table' => 'glpi_usercategories',
|
|
'field' => 'name',
|
|
'name' => __('Category'),
|
|
'datatype' => 'dropdown'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '79',
|
|
'table' => 'glpi_profiles',
|
|
'field' => 'name',
|
|
'name' => __('Default profile'),
|
|
'datatype' => 'dropdown'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '77',
|
|
'table' => 'glpi_entities',
|
|
'field' => 'name',
|
|
'massiveaction' => true,
|
|
'name' => __('Default entity'),
|
|
'datatype' => 'dropdown'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '62',
|
|
'table' => $this->getTable(),
|
|
'field' => 'begin_date',
|
|
'name' => __('Begin date'),
|
|
'datatype' => 'datetime'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '63',
|
|
'table' => $this->getTable(),
|
|
'field' => 'end_date',
|
|
'name' => __('End date'),
|
|
'datatype' => 'datetime'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '60',
|
|
'table' => 'glpi_tickets',
|
|
'field' => 'id',
|
|
'name' => __('Number of tickets as requester'),
|
|
'forcegroupby' => true,
|
|
'usehaving' => true,
|
|
'datatype' => 'count',
|
|
'massiveaction' => false,
|
|
'joinparams' => [
|
|
'beforejoin' => [
|
|
'table' => 'glpi_tickets_users',
|
|
'joinparams' => [
|
|
'jointype' => 'child',
|
|
'condition' => 'AND NEWTABLE.`type` = ' . CommonITILActor::REQUESTER
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '61',
|
|
'table' => 'glpi_tickets',
|
|
'field' => 'id',
|
|
'name' => __('Number of written tickets'),
|
|
'forcegroupby' => true,
|
|
'usehaving' => true,
|
|
'datatype' => 'count',
|
|
'massiveaction' => false,
|
|
'joinparams' => [
|
|
'jointype' => 'child',
|
|
'linkfield' => 'users_id_recipient'
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '64',
|
|
'table' => 'glpi_tickets',
|
|
'field' => 'id',
|
|
'name' => __('Number of assigned tickets'),
|
|
'forcegroupby' => true,
|
|
'usehaving' => true,
|
|
'datatype' => 'count',
|
|
'massiveaction' => false,
|
|
'joinparams' => [
|
|
'beforejoin' => [
|
|
'table' => 'glpi_tickets_users',
|
|
'joinparams' => [
|
|
'jointype' => 'child',
|
|
'condition' => 'AND NEWTABLE.`type` = '.CommonITILActor::ASSIGN
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '99',
|
|
'table' => 'glpi_users',
|
|
'field' => 'name',
|
|
'linkfield' => 'users_id_supervisor',
|
|
'name' => __('Responsible'),
|
|
'datatype' => 'dropdown',
|
|
'massiveaction' => false,
|
|
];
|
|
|
|
// add objectlock search options
|
|
$tab = array_merge($tab, ObjectLock::rawSearchOptionsToAdd(get_class($this)));
|
|
|
|
return $tab;
|
|
}
|
|
|
|
static function getSpecificValueToDisplay($field, $values, array $options = []) {
|
|
|
|
if (!is_array($values)) {
|
|
$values = [$field => $values];
|
|
}
|
|
switch ($field) {
|
|
case 'authtype':
|
|
$auths_id = 0;
|
|
if (isset($values['auths_id']) && !empty($values['auths_id'])) {
|
|
$auths_id = $values['auths_id'];
|
|
}
|
|
return Auth::getMethodName($values[$field], $auths_id);
|
|
case 'picture':
|
|
if (isset($options['html']) && $options['html']) {
|
|
return Html::image(self::getThumbnailURLForPicture($values['picture']),
|
|
['class' => 'user_picture_small', 'alt' => __('Picture')]);
|
|
}
|
|
}
|
|
return parent::getSpecificValueToDisplay($field, $values, $options);
|
|
}
|
|
|
|
static function getSpecificValueToSelect($field, $name = '', $values = '', array $options = []) {
|
|
|
|
if (!is_array($values)) {
|
|
$values = [$field => $values];
|
|
}
|
|
$options['display'] = false;
|
|
switch ($field) {
|
|
case 'authtype' :
|
|
$options['name'] = $name;
|
|
$options['value'] = $values[$field];
|
|
return Auth::dropdown($options);
|
|
}
|
|
return parent::getSpecificValueToSelect($field, $name, $values, $options);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all groups where the current user have delegating.
|
|
*
|
|
* @since 0.83
|
|
*
|
|
* @param integer|string $entities_id ID of the entity to restrict
|
|
*
|
|
* @return integer[]
|
|
*/
|
|
static function getDelegateGroupsForUser($entities_id = '') {
|
|
global $DB;
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => 'glpi_groups_users.groups_id',
|
|
'DISTINCT' => true,
|
|
'FROM' => 'glpi_groups_users',
|
|
'INNER JOIN' => [
|
|
'glpi_groups' => [
|
|
'FKEY' => [
|
|
'glpi_groups_users' => 'groups_id',
|
|
'glpi_groups' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_groups_users.users_id' => Session::getLoginUserID(),
|
|
'glpi_groups_users.is_userdelegate' => 1
|
|
] + getEntitiesRestrictCriteria('glpi_groups', '', $entities_id, 1)
|
|
]);
|
|
|
|
$groups = [];
|
|
while ($data = $iterator->next()) {
|
|
$groups[$data['groups_id']] = $data['groups_id'];
|
|
}
|
|
return $groups;
|
|
}
|
|
|
|
|
|
/**
|
|
* Execute the query to select box with all glpi users where select key = name
|
|
*
|
|
* Internaly used by showGroup_Users, dropdownUsers and ajax/getDropdownUsers.php
|
|
*
|
|
* @param boolean $count true if execute an count(*) (true by default)
|
|
* @param string|string[] $right limit user who have specific right (default 'all')
|
|
* @param integer $entity_restrict Restrict to a defined entity (default -1)
|
|
* @param integer $value default value (default 0)
|
|
* @param integer[] $used Already used items ID: not to display in dropdown
|
|
* @param string $search pattern (default '')
|
|
* @param integer $start start LIMIT value (default 0)
|
|
* @param integer $limit limit LIMIT value (default -1 no limit)
|
|
* @param boolean $inactive_deleted true to retreive also inactive or deleted users
|
|
*
|
|
* @return mysqli_result|boolean
|
|
*/
|
|
static function getSqlSearchResult ($count = true, $right = "all", $entity_restrict = -1, $value = 0,
|
|
array $used = [], $search = '', $start = 0, $limit = -1,
|
|
$inactive_deleted = 0) {
|
|
global $DB;
|
|
|
|
// No entity define : use active ones
|
|
if ($entity_restrict < 0) {
|
|
$entity_restrict = $_SESSION["glpiactiveentities"];
|
|
}
|
|
|
|
$joinprofile = false;
|
|
$joinprofileright = false;
|
|
$WHERE = [];
|
|
|
|
switch ($right) {
|
|
case "interface" :
|
|
$joinprofile = true;
|
|
$WHERE = [
|
|
'glpi_profiles.interface' => 'central'
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1);
|
|
break;
|
|
|
|
case "id" :
|
|
$WHERE = ['glpi_users.id' => Session::getLoginUserID()];
|
|
break;
|
|
|
|
case "delegate" :
|
|
$groups = self::getDelegateGroupsForUser($entity_restrict);
|
|
$users = [];
|
|
if (count($groups)) {
|
|
$iterator = $DB->request([
|
|
'SELECT' => 'glpi_users.id',
|
|
'FROM' => 'glpi_groups_users',
|
|
'LEFT JOIN' => [
|
|
'glpi_users' => [
|
|
'FKEY' => [
|
|
'glpi_groups_users' => 'users_id',
|
|
'glpi_users' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_groups_users.groups_id' => $groups,
|
|
'glpi_groups_users.users_id' => ['<>', Session::getLoginUserID()]
|
|
]
|
|
]);
|
|
while ($data = $iterator->next()) {
|
|
$users[$data["id"]] = $data["id"];
|
|
}
|
|
}
|
|
// Add me to users list for central
|
|
if (Session::getCurrentInterface() == 'central') {
|
|
$users[Session::getLoginUserID()] = Session::getLoginUserID();
|
|
}
|
|
|
|
if (count($users)) {
|
|
$WHERE = ['glpi_users.id' => $users];
|
|
}
|
|
break;
|
|
|
|
case "groups" :
|
|
$groups = [];
|
|
if (isset($_SESSION['glpigroups'])) {
|
|
$groups = $_SESSION['glpigroups'];
|
|
}
|
|
$users = [];
|
|
if (count($groups)) {
|
|
$iterator = $DB->request([
|
|
'SELECT' => 'glpi_users.id',
|
|
'FROM' => 'glpi_groups_users',
|
|
'LEFT JOIN' => [
|
|
'glpi_users' => [
|
|
'FKEY' => [
|
|
'glpi_groups_users' => 'users_id',
|
|
'glpi_users' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_groups_users.groups_id' => $groups,
|
|
'glpi_groups_users.users_id' => ['<>', Session::getLoginUserID()]
|
|
]
|
|
]);
|
|
while ($data = $iterator->next()) {
|
|
$users[$data["id"]] = $data["id"];
|
|
}
|
|
}
|
|
// Add me to users list for central
|
|
if (Session::getCurrentInterface() == 'central') {
|
|
$users[Session::getLoginUserID()] = Session::getLoginUserID();
|
|
}
|
|
|
|
if (count($users)) {
|
|
$WHERE = ['glpi_users.id' => $users];
|
|
}
|
|
|
|
break;
|
|
|
|
case "all" :
|
|
$WHERE = [
|
|
'glpi_users.id' => ['>', 0],
|
|
'OR' => [
|
|
'glpi_profiles_users.entities_id' => null
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
break;
|
|
|
|
default :
|
|
$joinprofile = true;
|
|
$joinprofileright = true;
|
|
if (!is_array($right)) {
|
|
$right = [$right];
|
|
}
|
|
$forcecentral = true;
|
|
|
|
$ORWHERE = [];
|
|
foreach ($right as $r) {
|
|
switch ($r) {
|
|
case 'own_ticket' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'ticket',
|
|
'glpi_profilerights.rights' => ['&', Ticket::OWN]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
break;
|
|
|
|
case 'create_ticket_validate' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'ticketvalidation',
|
|
'OR' => [
|
|
['glpi_profilerights.rights' => ['&', TicketValidation::CREATEREQUEST]],
|
|
['glpi_profilerights.rights' => ['&', TicketValidation::CREATEINCIDENT]]
|
|
]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
$forcecentral = false;
|
|
break;
|
|
|
|
case 'validate_request' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'ticketvalidation',
|
|
'glpi_profilerights.rights' => ['&', TicketValidation::VALIDATEREQUEST]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
$forcecentral = false;
|
|
break;
|
|
|
|
case 'validate_incident' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'ticketvalidation',
|
|
'glpi_profilerights.rights' => ['&', TicketValidation::VALIDATEINCIDENT]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
$forcecentral = false;
|
|
break;
|
|
|
|
case 'validate' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'changevalidation',
|
|
'glpi_profilerights.rights' => ['&', ChangeValidation::VALIDATE]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
break;
|
|
|
|
case 'create_validate' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'changevalidation',
|
|
'glpi_profilerights.rights' => ['&', ChangeValidation::CREATE]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
break;
|
|
|
|
case 'see_project' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'project',
|
|
'glpi_profilerights.rights' => ['&', Project::READMY]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
break;
|
|
|
|
case 'faq' :
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => 'knowbase',
|
|
'glpi_profilerights.rights' => ['&', KnowbaseItem::READFAQ]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
|
|
default :
|
|
// Check read or active for rights
|
|
$ORWHERE[] = [
|
|
[
|
|
'glpi_profilerights.name' => $r,
|
|
'glpi_profilerights.rights' => [
|
|
'&',
|
|
READ | CREATE | UPDATE | DELETE | PURGE
|
|
]
|
|
] + getEntitiesRestrictCriteria('glpi_profiles_users', '', $entity_restrict, 1)
|
|
];
|
|
}
|
|
if (in_array($r, Profile::$helpdesk_rights)) {
|
|
$forcecentral = false;
|
|
}
|
|
}
|
|
|
|
if (count($ORWHERE)) {
|
|
$WHERE[] = ['OR' => $ORWHERE];
|
|
}
|
|
|
|
if ($forcecentral) {
|
|
$WHERE['glpi_profiles.interface'] = 'central';
|
|
}
|
|
}
|
|
|
|
if (!$inactive_deleted) {
|
|
$WHERE = array_merge(
|
|
$WHERE, [
|
|
'glpi_users.is_deleted' => 0,
|
|
'glpi_users.is_active' => 1,
|
|
[
|
|
'OR' => [
|
|
['glpi_users.begin_date' => null],
|
|
['glpi_users.begin_date' => ['<', new QueryExpression('NOW()')]]
|
|
]
|
|
],
|
|
[
|
|
'OR' => [
|
|
['glpi_users.end_date' => null],
|
|
['glpi_users.end_date' => ['>', new QueryExpression('NOW()')]]
|
|
]
|
|
]
|
|
|
|
]
|
|
);
|
|
}
|
|
|
|
if ((is_numeric($value) && $value)
|
|
|| count($used)) {
|
|
|
|
$WHERE[] = [
|
|
'NOT' => [
|
|
'glpi_users.id' => $used
|
|
]
|
|
];
|
|
}
|
|
|
|
$criteria = [
|
|
'FROM' => 'glpi_users',
|
|
'LEFT JOIN' => [
|
|
'glpi_useremails' => [
|
|
'ON' => [
|
|
'glpi_useremails' => 'users_id',
|
|
'glpi_users' => 'id'
|
|
]
|
|
],
|
|
'glpi_profiles_users' => [
|
|
'ON' => [
|
|
'glpi_profiles_users' => 'users_id',
|
|
'glpi_users' => 'id'
|
|
]
|
|
]
|
|
]
|
|
];
|
|
if ($count) {
|
|
$criteria['SELECT'] = ['COUNT' => 'glpi_users.id AS CPT'];
|
|
$criteria['DISTINCT'] = true;
|
|
} else {
|
|
$criteria['SELECT'] = 'glpi_users.*';
|
|
$criteria['DISTINCT'] = true;
|
|
}
|
|
|
|
if ($joinprofile) {
|
|
$criteria['LEFT JOIN']['glpi_profiles'] = [
|
|
'ON' => [
|
|
'glpi_profiles_users' => 'profiles_id',
|
|
'glpi_profiles' => 'id'
|
|
]
|
|
];
|
|
if ($joinprofileright) {
|
|
$criteria['LEFT JOIN']['glpi_profilerights'] = [
|
|
'ON' => [
|
|
'glpi_profilerights' => 'profiles_id',
|
|
'glpi_profiles' => 'id'
|
|
]
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!$count) {
|
|
if ((strlen($search) > 0)) {
|
|
$txt_search = Search::makeTextSearchValue($search);
|
|
|
|
$firstname_field = $DB->quoteName(self::getTableField('firstname'));
|
|
$realname_field = $DB->quoteName(self::getTableField('realname'));
|
|
$fields = $_SESSION["glpinames_format"] == self::FIRSTNAME_BEFORE
|
|
? [$firstname_field, $realname_field]
|
|
: [$realname_field, $firstname_field];
|
|
|
|
$concat = new \QueryExpression(
|
|
'CONCAT(' . implode(',' . $DB->quoteValue(' ') . ',', $fields) . ')'
|
|
. ' LIKE ' . $DB->quoteValue($txt_search)
|
|
);
|
|
$WHERE[] = [
|
|
'OR' => [
|
|
'glpi_users.name' => ['LIKE', $txt_search],
|
|
'glpi_users.realname' => ['LIKE', $txt_search],
|
|
'glpi_users.firstname' => ['LIKE', $txt_search],
|
|
'glpi_users.phone' => ['LIKE', $txt_search],
|
|
'glpi_useremails.email' => ['LIKE', $txt_search],
|
|
$concat
|
|
]
|
|
];
|
|
}
|
|
|
|
if ($_SESSION["glpinames_format"] == self::FIRSTNAME_BEFORE) {
|
|
$criteria['ORDERBY'] = [
|
|
'glpi_users.firstname',
|
|
'glpi_users.realname',
|
|
'glpi_users.name'
|
|
];
|
|
} else {
|
|
$criteria['ORDERBY'] = [
|
|
'glpi_users.realname',
|
|
'glpi_users.firstname',
|
|
'glpi_users.name'
|
|
];
|
|
}
|
|
|
|
if ($limit > 0) {
|
|
$criteria['LIMIT'] = $limit;
|
|
$criteria['START'] = $start;
|
|
}
|
|
}
|
|
$criteria['WHERE'] = $WHERE;
|
|
return $DB->request($criteria);
|
|
}
|
|
|
|
|
|
/**
|
|
* Make a select box with all glpi users where select key = name
|
|
*
|
|
* @param $options array of possible options:
|
|
* - name : string / name of the select (default is users_id)
|
|
* - value
|
|
* - values : in case of select[multiple], pass the array of multiple values
|
|
* - right : string / limit user who have specific right :
|
|
* id -> only current user (default case);
|
|
* interface -> central;
|
|
* all -> all users;
|
|
* specific right like Ticket::READALL, CREATE.... (is array passed one of all passed right is needed)
|
|
* - comments : boolean / is the comments displayed near the dropdown (default true)
|
|
* - entity : integer or array / restrict to a defined entity or array of entities
|
|
* (default -1 : no restriction)
|
|
* - entity_sons : boolean / if entity restrict specified auto select its sons
|
|
* only available if entity is a single value not an array(default false)
|
|
* - all : Nobody or All display for none selected
|
|
* all=0 (default) -> Nobody
|
|
* all=1 -> All
|
|
* all=-1-> nothing
|
|
* - rand : integer / already computed rand value
|
|
* - toupdate : array / Update a specific item on select change on dropdown
|
|
* (need value_fieldname, to_update, url
|
|
* (see Ajax::updateItemOnSelectEvent for information)
|
|
* and may have moreparams)
|
|
* - used : array / Already used items ID: not to display in dropdown (default empty)
|
|
* - ldap_import
|
|
* - on_change : string / value to transmit to "onChange"
|
|
* - display : boolean / display or get string (default true)
|
|
* - width : specific width needed (default 80%)
|
|
* - specific_tags : array of HTML5 tags to add to the field
|
|
* - url : url of the ajax php code which should return the json data to show in
|
|
* the dropdown (default /ajax/getDropdownUsers.php)
|
|
* - inactive_deleted : retreive also inactive or deleted users
|
|
*
|
|
* @return integer|string Random value if displayed, string otherwise
|
|
*/
|
|
static function dropdown($options = []) {
|
|
global $CFG_GLPI;
|
|
|
|
// Default values
|
|
$p = [
|
|
'name' => 'users_id',
|
|
'value' => '',
|
|
'values' => [],
|
|
'right' => 'id',
|
|
'all' => 0,
|
|
'display_emptychoice' => true,
|
|
'on_change' => '',
|
|
'comments' => 1,
|
|
'width' => '80%',
|
|
'entity' => -1,
|
|
'entity_sons' => false,
|
|
'used' => [],
|
|
'ldap_import' => false,
|
|
'toupdate' => '',
|
|
'rand' => mt_rand(),
|
|
'display' => true,
|
|
'_user_index' => 0,
|
|
'specific_tags' => [],
|
|
'url' => $CFG_GLPI['root_doc'] . "/ajax/getDropdownUsers.php",
|
|
'inactive_deleted' => 0,
|
|
];
|
|
|
|
if (is_array($options) && count($options)) {
|
|
foreach ($options as $key => $val) {
|
|
$p[$key] = $val;
|
|
}
|
|
}
|
|
|
|
// check default value (in case of multiple observers)
|
|
if (is_array($p['value'])) {
|
|
$p['value'] = $p['value'][$p['_user_index']] ?? 0;
|
|
}
|
|
|
|
// Check default value for dropdown : need to be a numeric
|
|
if ((strlen($p['value']) == 0) || !is_numeric($p['value'])) {
|
|
$p['value'] = 0;
|
|
}
|
|
|
|
$output = '';
|
|
if (!($p['entity'] < 0) && $p['entity_sons']) {
|
|
if (is_array($p['entity'])) {
|
|
$output .= "entity_sons options is not available with array of entity";
|
|
} else {
|
|
$p['entity'] = getSonsOf('glpi_entities', $p['entity']);
|
|
}
|
|
}
|
|
|
|
// Make a select box with all glpi users
|
|
$user = getUserName($p['value'], 2);
|
|
|
|
$view_users = self::canView();
|
|
|
|
if (!empty($p['value']) && ($p['value'] > 0)) {
|
|
$default = $user["name"];
|
|
} else {
|
|
if ($p['all']) {
|
|
$default = __('All');
|
|
} else {
|
|
$default = Dropdown::EMPTY_VALUE;
|
|
}
|
|
}
|
|
|
|
// get multiple values name
|
|
$valuesnames = [];
|
|
foreach ($p['values'] as $value) {
|
|
if (!empty($value) && ($value > 0)) {
|
|
$user = getUserName($value, 2);
|
|
$valuesnames[] = $user["name"];
|
|
}
|
|
}
|
|
|
|
$field_id = Html::cleanId("dropdown_" . $p['name'] . $p['rand']);
|
|
$param = ['value' => $p['value'],
|
|
'values' => $p['values'],
|
|
'valuename' => $default,
|
|
'valuesnames' => $valuesnames,
|
|
'width' => $p['width'],
|
|
'all' => $p['all'],
|
|
'display_emptychoice' => $p['display_emptychoice'],
|
|
'right' => $p['right'],
|
|
'on_change' => $p['on_change'],
|
|
'used' => $p['used'],
|
|
'inactive_deleted' => $p['inactive_deleted'],
|
|
'entity_restrict' => (is_array($p['entity']) ? json_encode(array_values($p['entity'])) : $p['entity']),
|
|
'specific_tags' => $p['specific_tags']];
|
|
|
|
$output = Html::jsAjaxDropdown($p['name'], $field_id,
|
|
$p['url'],
|
|
$param);
|
|
|
|
// Display comment
|
|
if ($p['comments']) {
|
|
$comment_id = Html::cleanId("comment_".$p['name'].$p['rand']);
|
|
$link_id = Html::cleanId("comment_link_".$p["name"].$p['rand']);
|
|
if (!$view_users) {
|
|
$user["link"] = '';
|
|
} else if (empty($user["link"])) {
|
|
$user["link"] = $CFG_GLPI['root_doc']."/front/user.php";
|
|
}
|
|
|
|
if (empty($user['comment'])) {
|
|
$user['comment'] = Toolbox::ucfirst(
|
|
sprintf(
|
|
__('Show %1$s'),
|
|
self::getTypeName(Session::getPluralNumber())
|
|
)
|
|
);
|
|
}
|
|
$output .= " ".Html::showToolTip($user["comment"],
|
|
['contentid' => $comment_id,
|
|
'display' => false,
|
|
'link' => $user["link"],
|
|
'linkid' => $link_id]);
|
|
|
|
$paramscomment = ['value' => '__VALUE__',
|
|
'table' => "glpi_users"];
|
|
|
|
if ($view_users) {
|
|
$paramscomment['withlink'] = $link_id;
|
|
}
|
|
$output .= Ajax::updateItemOnSelectEvent($field_id, $comment_id,
|
|
$CFG_GLPI["root_doc"]."/ajax/comments.php",
|
|
$paramscomment, false);
|
|
}
|
|
$output .= Ajax::commonDropdownUpdateItem($p, false);
|
|
|
|
if (Session::haveRight('user', self::IMPORTEXTAUTHUSERS)
|
|
&& $p['ldap_import']
|
|
&& Entity::isEntityDirectoryConfigured($_SESSION['glpiactive_entity'])) {
|
|
|
|
$output .= "<span title=\"".__s('Import a user')."\" class='fa fa-plus pointer'".
|
|
" onClick=\"".Html::jsGetElementbyID('userimport'.$p['rand']).".dialog('open');\">
|
|
<span class='sr-only'>" . __s('Import a user') . "</span></span>";
|
|
$output .= Ajax::createIframeModalWindow('userimport'.$p['rand'],
|
|
$CFG_GLPI["root_doc"].
|
|
"/front/ldap.import.php?entity=".
|
|
$_SESSION['glpiactive_entity'],
|
|
['title' => __('Import a user'),
|
|
'display' => false]);
|
|
}
|
|
|
|
if ($p['display']) {
|
|
echo $output;
|
|
return $p['rand'];
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
|
|
/**
|
|
* Show simple add user form for external auth.
|
|
*
|
|
* @return void|boolean false if user does not have rights to import users from external sources,
|
|
* print form otherwise
|
|
*/
|
|
static function showAddExtAuthForm() {
|
|
|
|
if (!Session::haveRight("user", self::IMPORTEXTAUTHUSERS)) {
|
|
return false;
|
|
}
|
|
|
|
echo "<div class='center'>\n";
|
|
echo "<form method='post' action='".Toolbox::getItemTypeFormURL('User')."'>\n";
|
|
|
|
echo "<table class='tab_cadre'>\n";
|
|
echo "<tr><th colspan='4'>".__('Automatically add a user of an external source')."</th></tr>\n";
|
|
|
|
echo "<tr class='tab_bg_1'><td>".__('Login')."</td>\n";
|
|
echo "<td><input type='text' name='login'></td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td class='tab_bg_2 center' colspan='2'>\n";
|
|
echo "<input type='submit' name='add_ext_auth_ldap' value=\"".__s('Import from directories')."\"
|
|
class='submit'>\n";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td class='tab_bg_2 center' colspan='2'>\n";
|
|
echo "<input type='submit' name='add_ext_auth_simple' value=\"".__s('Import from other sources')."\"
|
|
class='submit'>\n";
|
|
echo "</td></tr>\n";
|
|
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>\n";
|
|
}
|
|
|
|
|
|
/**
|
|
* Change auth method for given users.
|
|
*
|
|
* @param integer[] $IDs IDs of users
|
|
* @param integer $authtype Auth type (see Auth constants)
|
|
* @param integer $server ID of auth server
|
|
*
|
|
* @return boolean
|
|
*/
|
|
static function changeAuthMethod(array $IDs = [], $authtype = 1, $server = -1) {
|
|
global $DB;
|
|
|
|
if (!Session::haveRight(self::$rightname, self::UPDATEAUTHENT)) {
|
|
return false;
|
|
}
|
|
|
|
if (!empty($IDs)
|
|
&& in_array($authtype, [Auth::DB_GLPI, Auth::LDAP, Auth::MAIL, Auth::EXTERNAL])) {
|
|
|
|
$result = $DB->update(
|
|
self::getTable(), [
|
|
'authtype' => $authtype,
|
|
'auths_id' => $server,
|
|
'password' => '',
|
|
'is_deleted_ldap' => 0
|
|
], [
|
|
'id' => $IDs
|
|
]
|
|
);
|
|
if ($result) {
|
|
foreach ($IDs as $ID) {
|
|
$changes = [
|
|
0,
|
|
'',
|
|
addslashes(
|
|
sprintf(
|
|
__('%1$s: %2$s'),
|
|
__('Update authentification method to'),
|
|
Auth::getMethodName($authtype, $server)
|
|
)
|
|
)
|
|
];
|
|
Log::history($ID, __CLASS__, $changes, '', Log::HISTORY_LOG_SIMPLE_MESSAGE);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Generate vcard for the current user.
|
|
*
|
|
* @return void
|
|
*/
|
|
function generateVcard() {
|
|
|
|
// prepare properties for the Vcard
|
|
if (!empty($this->fields["realname"])
|
|
|| !empty($this->fields["firstname"])) {
|
|
$name = [$this->fields["realname"], $this->fields["firstname"], "", "", ""];
|
|
} else {
|
|
$name = [$this->fields["name"], "", "", "", ""];
|
|
}
|
|
|
|
// create vcard
|
|
$vcard = new VObject\Component\VCard([
|
|
'N' => $name,
|
|
'EMAIL' => $this->getDefaultEmail(),
|
|
'NOTE' => $this->fields["comment"],
|
|
]);
|
|
$vcard->add('TEL', $this->fields["phone"], ['type' => 'PREF;WORK;VOICE']);
|
|
$vcard->add('TEL', $this->fields["phone2"], ['type' => 'HOME;VOICE']);
|
|
$vcard->add('TEL', $this->fields["mobile"], ['type' => 'WORK;CELL']);
|
|
|
|
// send the VCard
|
|
$output = $vcard->serialize();
|
|
$filename = implode("_", array_filter($name)).".vcf";
|
|
|
|
@header("Content-Disposition: attachment; filename=\"$filename\"");
|
|
@header("Content-Length: ".Toolbox::strlen($output));
|
|
@header("Connection: close");
|
|
@header("content-type: text/x-vcard; charset=UTF-8");
|
|
|
|
echo $output;
|
|
}
|
|
|
|
|
|
/**
|
|
* Show items of the current user.
|
|
*
|
|
* @param boolean $tech false to display items owned by user, true to display items managed by user
|
|
*
|
|
* @return void
|
|
*/
|
|
function showItems($tech) {
|
|
global $DB, $CFG_GLPI;
|
|
|
|
$ID = $this->getField('id');
|
|
|
|
if ($tech) {
|
|
$type_user = $CFG_GLPI['linkuser_tech_types'];
|
|
$type_group = $CFG_GLPI['linkgroup_tech_types'];
|
|
$field_user = 'users_id_tech';
|
|
$field_group = 'groups_id_tech';
|
|
} else {
|
|
$type_user = $CFG_GLPI['linkuser_types'];
|
|
$type_group = $CFG_GLPI['linkgroup_types'];
|
|
$field_user = 'users_id';
|
|
$field_group = 'groups_id';
|
|
}
|
|
|
|
$group_where = "";
|
|
$groups = [];
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => [
|
|
'glpi_groups_users.groups_id',
|
|
'glpi_groups.name'
|
|
],
|
|
'FROM' => 'glpi_groups_users',
|
|
'LEFT JOIN' => [
|
|
'glpi_groups' => [
|
|
'FKEY' => [
|
|
'glpi_groups_users' => 'groups_id',
|
|
'glpi_groups' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => ['glpi_groups_users.users_id' => $ID]
|
|
]);
|
|
$number = count($iterator);
|
|
|
|
$group_where = [];
|
|
while ($data = $iterator->next()) {
|
|
$group_where[$field_group][] = $data['groups_id'];
|
|
$groups[$data["groups_id"]] = $data["name"];
|
|
}
|
|
|
|
echo "<div class='spaced'><table class='tab_cadre_fixehov'>";
|
|
$header = "<tr><th>"._n('Type', 'Types', 1)."</th>";
|
|
$header .= "<th>".Entity::getTypeName(1)."</th>";
|
|
$header .= "<th>".__('Name')."</th>";
|
|
$header .= "<th>".__('Serial number')."</th>";
|
|
$header .= "<th>".__('Inventory number')."</th>";
|
|
$header .= "<th>".__('Status')."</th>";
|
|
$header .= "<th> </th></tr>";
|
|
echo $header;
|
|
|
|
foreach ($type_user as $itemtype) {
|
|
if (!($item = getItemForItemtype($itemtype))) {
|
|
continue;
|
|
}
|
|
if ($item->canView()) {
|
|
$itemtable = getTableForItemType($itemtype);
|
|
$iterator_params = [
|
|
'FROM' => $itemtable,
|
|
'WHERE' => [$field_user => $ID]
|
|
];
|
|
|
|
if ($item->maybeTemplate()) {
|
|
$iterator_params['WHERE']['is_template'] = 0;
|
|
}
|
|
if ($item->maybeDeleted()) {
|
|
$iterator_params['WHERE']['is_deleted'] = 0;
|
|
}
|
|
|
|
$item_iterator = $DB->request($iterator_params);
|
|
|
|
$type_name = $item->getTypeName();
|
|
|
|
while ($data = $item_iterator->next()) {
|
|
$cansee = $item->can($data["id"], READ);
|
|
$link = $data["name"];
|
|
if ($cansee) {
|
|
$link_item = $item::getFormURLWithID($data['id']);
|
|
if ($_SESSION["glpiis_ids_visible"] || empty($link)) {
|
|
$link = sprintf(__('%1$s (%2$s)'), $link, $data["id"]);
|
|
}
|
|
$link = "<a href='".$link_item."'>".$link."</a>";
|
|
}
|
|
$linktype = "";
|
|
if ($data[$field_user] == $ID) {
|
|
$linktype = self::getTypeName(1);
|
|
}
|
|
echo "<tr class='tab_bg_1'><td class='center'>$type_name</td>";
|
|
echo "<td class='center'>".Dropdown::getDropdownName("glpi_entities",
|
|
$data["entities_id"])."</td>";
|
|
echo "<td class='center'>$link</td>";
|
|
echo "<td class='center'>";
|
|
if (isset($data["serial"]) && !empty($data["serial"])) {
|
|
echo $data["serial"];
|
|
} else {
|
|
echo ' ';
|
|
}
|
|
echo "</td><td class='center'>";
|
|
if (isset($data["otherserial"]) && !empty($data["otherserial"])) {
|
|
echo $data["otherserial"];
|
|
} else {
|
|
echo ' ';
|
|
}
|
|
echo "</td><td class='center'>";
|
|
if (isset($data["states_id"])) {
|
|
echo Dropdown::getDropdownName("glpi_states", $data['states_id']);
|
|
} else {
|
|
echo ' ';
|
|
}
|
|
|
|
echo "</td><td class='center'>$linktype</td></tr>";
|
|
}
|
|
}
|
|
}
|
|
if ($number) {
|
|
echo $header;
|
|
}
|
|
echo "</table></div>";
|
|
|
|
if (count($group_where)) {
|
|
echo "<div class='spaced'><table class='tab_cadre_fixehov'>";
|
|
$header = "<tr>".
|
|
"<th>"._n('Type', 'Types', 1)."</th>".
|
|
"<th>".Entity::getTypeName(1)."</th>".
|
|
"<th>".__('Name')."</th>".
|
|
"<th>".__('Serial number')."</th>".
|
|
"<th>".__('Inventory number')."</th>".
|
|
"<th>".__('Status')."</th>".
|
|
"<th> </th></tr>";
|
|
echo $header;
|
|
$nb = 0;
|
|
foreach ($type_group as $itemtype) {
|
|
if (!($item = getItemForItemtype($itemtype))) {
|
|
continue;
|
|
}
|
|
if ($item->canView() && $item->isField($field_group)) {
|
|
$itemtable = getTableForItemType($itemtype);
|
|
$iterator_params = [
|
|
'FROM' => $itemtable,
|
|
'WHERE' => ['OR' => $group_where]
|
|
];
|
|
|
|
if ($item->maybeTemplate()) {
|
|
$iterator_params['WHERE']['is_template'] = 0;
|
|
}
|
|
if ($item->maybeDeleted()) {
|
|
$iterator_params['WHERE']['is_deleted'] = 0;
|
|
}
|
|
|
|
$group_iterator = $DB->request($iterator_params);
|
|
|
|
$type_name = $item->getTypeName();
|
|
|
|
while ($data = $group_iterator->next()) {
|
|
$nb++;
|
|
$cansee = $item->can($data["id"], READ);
|
|
$link = $data["name"];
|
|
if ($cansee) {
|
|
$link_item = $item::getFormURLWithID($data['id']);
|
|
if ($_SESSION["glpiis_ids_visible"] || empty($link)) {
|
|
$link = sprintf(__('%1$s (%2$s)'), $link, $data["id"]);
|
|
}
|
|
$link = "<a href='".$link_item."'>".$link."</a>";
|
|
}
|
|
$linktype = "";
|
|
if (isset($groups[$data[$field_group]])) {
|
|
$linktype = sprintf(__('%1$s = %2$s'), Group::getTypeName(1),
|
|
$groups[$data[$field_group]]);
|
|
}
|
|
echo "<tr class='tab_bg_1'><td class='center'>$type_name</td>";
|
|
echo "<td class='center'>".Dropdown::getDropdownName("glpi_entities",
|
|
$data["entities_id"]);
|
|
echo "</td><td class='center'>$link</td>";
|
|
echo "<td class='center'>";
|
|
if (isset($data["serial"]) && !empty($data["serial"])) {
|
|
echo $data["serial"];
|
|
} else {
|
|
echo ' ';
|
|
}
|
|
echo "</td><td class='center'>";
|
|
if (isset($data["otherserial"]) && !empty($data["otherserial"])) {
|
|
echo $data["otherserial"];
|
|
} else {
|
|
echo ' ';
|
|
}
|
|
echo "</td><td class='center'>";
|
|
if (isset($data["states_id"])) {
|
|
echo Dropdown::getDropdownName("glpi_states", $data['states_id']);
|
|
} else {
|
|
echo ' ';
|
|
}
|
|
|
|
echo "</td><td class='center'>$linktype</td></tr>";
|
|
}
|
|
}
|
|
}
|
|
if ($nb) {
|
|
echo $header;
|
|
}
|
|
echo "</table></div>";
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get user by email, importing it from LDAP if not existing.
|
|
*
|
|
* @param string $email
|
|
*
|
|
* @return integer ID of user, 0 if not found nor imported
|
|
*/
|
|
static function getOrImportByEmail($email = '') {
|
|
global $DB, $CFG_GLPI;
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => 'users_id AS id',
|
|
'FROM' => 'glpi_useremails',
|
|
'LEFT JOIN' => [
|
|
'glpi_users' => [
|
|
'FKEY' => [
|
|
'glpi_useremails' => 'users_id',
|
|
'glpi_users' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_useremails.email' => $DB->escape(stripslashes($email))
|
|
],
|
|
'ORDER' => ['glpi_users.is_active DESC', 'is_deleted ASC']
|
|
]);
|
|
|
|
//User still exists in DB
|
|
if (count($iterator)) {
|
|
$result = $iterator->next();
|
|
return $result['id'];
|
|
} else {
|
|
if ($CFG_GLPI["is_users_auto_add"]) {
|
|
//Get all ldap servers with email field configured
|
|
$ldaps = AuthLDAP::getServersWithImportByEmailActive();
|
|
//Try to find the user by his email on each ldap server
|
|
|
|
foreach ($ldaps as $ldap) {
|
|
$params = [
|
|
'method' => AuthLDAP::IDENTIFIER_EMAIL,
|
|
'value' => $email,
|
|
];
|
|
$res = AuthLDAP::ldapImportUserByServerId($params,
|
|
AuthLDAP::ACTION_IMPORT,
|
|
$ldap);
|
|
|
|
if (isset($res['id'])) {
|
|
return $res['id'];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle user deleted in LDAP using configured policy.
|
|
*
|
|
* @param integer $users_id
|
|
*
|
|
* @return void
|
|
*/
|
|
static function manageDeletedUserInLdap($users_id) {
|
|
global $CFG_GLPI;
|
|
|
|
//The only case where users_id can be null if when a user has been imported into GLPI
|
|
//it's dn still exists, but doesn't match the connection filter anymore
|
|
//In this case, do not try to process the user
|
|
if (!$users_id) {
|
|
return;
|
|
}
|
|
|
|
//User is present in DB but not in the directory : it's been deleted in LDAP
|
|
$tmp = [
|
|
'id' => $users_id,
|
|
'is_deleted_ldap' => 1,
|
|
];
|
|
$myuser = new self();
|
|
$myuser->getFromDB($users_id);
|
|
|
|
//User is already considered as delete from ldap
|
|
if ($myuser->fields['is_deleted_ldap'] == 1) {
|
|
return;
|
|
}
|
|
|
|
switch ($CFG_GLPI['user_deleted_ldap']) {
|
|
//DO nothing
|
|
default :
|
|
case AuthLDAP::DELETED_USER_PRESERVE:
|
|
$myuser->update($tmp);
|
|
break;
|
|
|
|
//Put user in trashbin
|
|
case AuthLDAP::DELETED_USER_DELETE:
|
|
$myuser->delete($tmp);
|
|
break;
|
|
|
|
//Delete all user dynamic habilitations and groups
|
|
case AuthLDAP::DELETED_USER_WITHDRAWDYNINFO:
|
|
Profile_User::deleteRights($users_id, true);
|
|
Group_User::deleteGroups($users_id, true);
|
|
$myuser->update($tmp);
|
|
break;
|
|
|
|
//Deactivate the user
|
|
case AuthLDAP::DELETED_USER_DISABLE:
|
|
$tmp['is_active'] = 0;
|
|
$myuser->update($tmp);
|
|
break;
|
|
|
|
//Deactivate the user+ Delete all user dynamic habilitations and groups
|
|
case AuthLDAP::DELETED_USER_DISABLEANDWITHDRAWDYNINFO:
|
|
$tmp['is_active'] = 0;
|
|
$myuser->update($tmp);
|
|
Profile_User::deleteRights($users_id, true);
|
|
Group_User::deleteGroups($users_id, true);
|
|
break;
|
|
|
|
}
|
|
/*
|
|
$changes[0] = '0';
|
|
$changes[1] = '';
|
|
$changes[2] = __('Deleted user in LDAP directory');
|
|
Log::history($users_id, 'User', $changes, 0, Log::HISTORY_LOG_SIMPLE_MESSAGE);*/
|
|
}
|
|
|
|
/**
|
|
* Get user ID from its name.
|
|
*
|
|
* @param string $name User name
|
|
*
|
|
* @return integer
|
|
*/
|
|
static function getIdByName($name) {
|
|
return self::getIdByField('name', $name);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get user ID from a field
|
|
*
|
|
* @since 0.84
|
|
*
|
|
* @param string $field Field name
|
|
* @param string $value Field value
|
|
*
|
|
* @return integer
|
|
*/
|
|
static function getIdByField($field, $value, $escape = true) {
|
|
global $DB;
|
|
|
|
if ($escape) {
|
|
$value = addslashes($value);
|
|
}
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => 'id',
|
|
'FROM' => self::getTable(),
|
|
'WHERE' => [$field => $value]
|
|
]);
|
|
|
|
if (count($iterator) == 1) {
|
|
$row = $iterator->next();
|
|
return (int)$row['id'];
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Show password update form for current user.
|
|
*
|
|
* @param array $error_messages
|
|
*
|
|
* @return void
|
|
*/
|
|
public function showPasswordUpdateForm(array $error_messages = []) {
|
|
global $CFG_GLPI;
|
|
|
|
echo '<form method="post" action="' . $CFG_GLPI['root_doc'] . '/front/updatepassword.php">';
|
|
echo '<table class="tab_cadre">';
|
|
echo '<tr><th colspan="2">' . __('Password update') . '</th></tr>';
|
|
|
|
if (Session::mustChangePassword()) {
|
|
echo '<tr class="tab_bg_2 center">';
|
|
echo '<td colspan="2" class="red b">';
|
|
echo __('Your password has expired. You must change it to be able to login.');
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
}
|
|
|
|
echo '<tr class="tab_bg_1">';
|
|
echo '<td>';
|
|
echo __('Login');
|
|
echo '</td>';
|
|
echo '<td>';
|
|
echo '<input type="text" name="name" value="' . $this->fields['name'] . '" readonly="readonly" />';
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
|
|
echo '<tr class="tab_bg_1">';
|
|
echo '<td>';
|
|
echo '<label for="current_password">' . __('Current password') . '</label>';
|
|
echo '</td>';
|
|
echo '<td>';
|
|
echo '<input type="password" id="current_password" name="current_password" />';
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
|
|
echo '<tr class="tab_bg_1">';
|
|
echo '<td>';
|
|
echo '<label for="password">' . __('New password') . '</label>';
|
|
echo '</td>';
|
|
echo '<td>';
|
|
echo '<input type="password" id="password" name="password" autocomplete="new-password" onkeyup="return passwordCheck();" />';
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
|
|
echo '<tr class="tab_bg_1">';
|
|
echo '<td>';
|
|
echo '<label for="password2">' . __('New password confirmation') . '</label>';
|
|
echo '</td>';
|
|
echo '<td>';
|
|
echo '<input type="password" id="password2" name="password2" autocomplete="new-password" />';
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
|
|
if ($CFG_GLPI['use_password_security']) {
|
|
echo '<tr class="tab_bg_1">';
|
|
echo '<td>' . __('Password security policy') . '</td>';
|
|
echo '<td>';
|
|
Config::displayPasswordSecurityChecks();
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
}
|
|
|
|
echo '<tr class="tab_bg_2 center">';
|
|
echo '<td colspan="2">';
|
|
echo '<input type="submit" name="update" value="' . __s('Save') . '" class="submit" />';
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
|
|
if (!empty($error_messages)) {
|
|
echo '<tr class="tab_bg_2 center">';
|
|
echo '<td colspan="2" class="red b">';
|
|
echo implode('<br/>', $error_messages);
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
}
|
|
|
|
echo '</table>';
|
|
Html::closeForm();
|
|
}
|
|
|
|
|
|
/**
|
|
* Show new password form of password recovery process.
|
|
*
|
|
* @param $token
|
|
*
|
|
* @return void
|
|
*/
|
|
static function showPasswordForgetChangeForm($token) {
|
|
global $CFG_GLPI, $DB;
|
|
|
|
// Verif token.
|
|
$token_ok = false;
|
|
$iterator = $DB->request([
|
|
'FROM' => self::getTable(),
|
|
'WHERE' => [
|
|
'password_forget_token' => $token,
|
|
new \QueryExpression('NOW() < ADDDATE(' . $DB->quoteName('password_forget_token_date') . ', INTERVAL 1 DAY)')
|
|
]
|
|
]);
|
|
|
|
if (count($iterator) == 1) {
|
|
$token_ok = true;
|
|
}
|
|
echo "<div class='center'>";
|
|
|
|
if ($token_ok) {
|
|
echo "<form method='post' name='forgetpassword' action='".$CFG_GLPI['root_doc'].
|
|
"/front/lostpassword.php'>";
|
|
echo "<table class='tab_cadre'>";
|
|
echo "<tr><th colspan='2'>" . __('Forgotten password?')."</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'>";
|
|
echo "<td colspan='2'>". __('Please confirm your email address and enter your new password.').
|
|
"</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . _n('Email', 'Emails', 1)."</td>";
|
|
echo "<td><input type='text' name='email' value='' size='60'></td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Password')."</td>";
|
|
echo "<td><input id='password' type='password' name='password' value='' size='20'
|
|
autocomplete='new-password' onkeyup=\"return passwordCheck();\">";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>" . __('Password confirmation')."</td>";
|
|
echo "<td><input type='password' name='password2' value='' size='20' autocomplete='new-password'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td>".__('Password security policy')."</td>";
|
|
echo "<td>";
|
|
Config::displayPasswordSecurityChecks();
|
|
echo "</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2 center'><td colspan='2'>";
|
|
echo "<input type='hidden' name='password_forget_token' value='$token'>";
|
|
echo "<input type='submit' name='update' value=\"".__s('Save')."\" class='submit'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
|
|
} else {
|
|
echo __('Your password reset request has expired or is invalid. Please renew it.');
|
|
}
|
|
echo "</div>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Show request form of password recovery process.
|
|
*
|
|
* @return void
|
|
*/
|
|
static function showPasswordForgetRequestForm() {
|
|
global $CFG_GLPI;
|
|
|
|
echo "<div class='center'>";
|
|
echo "<form method='post' name='forgetpassword' action='".$CFG_GLPI['root_doc'].
|
|
"/front/lostpassword.php'>";
|
|
echo "<table class='tab_cadre'>";
|
|
echo "<tr><th colspan='2'>" . __('Forgotten password?')."</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td colspan='2'>" .
|
|
__('Please enter your email address. An email will be sent to you and you will be able to choose a new password.').
|
|
"</td></tr>";
|
|
|
|
echo "<tr class='tab_bg_2 center'>";
|
|
echo "<td><input type='text' size='60' name='email' value=''></td>";
|
|
echo "<td><input type='submit' name='update' value=\"".__s('Save')."\" class='submit'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Handle password recovery form submission.
|
|
*
|
|
* @param array $input
|
|
*
|
|
* @throws ForgetPasswordException when requirements are not met
|
|
*
|
|
* @return boolean true if password successfully changed, false otherwise
|
|
*/
|
|
public function updateForgottenPassword(array $input) {
|
|
$condition = [
|
|
'glpi_users.is_active' => 1,
|
|
'glpi_users.is_deleted' => 0, [
|
|
'OR' => [
|
|
['glpi_users.begin_date' => null],
|
|
['glpi_users.begin_date' => ['<', new QueryExpression('NOW()')]]
|
|
],
|
|
], [
|
|
'OR' => [
|
|
['glpi_users.end_date' => null],
|
|
['glpi_users.end_date' => ['>', new QueryExpression('NOW()')]]
|
|
]
|
|
]
|
|
];
|
|
if ($this->getFromDBbyEmail($input['email'], $condition)) {
|
|
if (($this->fields["authtype"] == Auth::DB_GLPI)
|
|
|| !Auth::useAuthExt()) {
|
|
|
|
if (($input['password_forget_token'] == $this->fields['password_forget_token'])
|
|
&& (abs(strtotime($_SESSION["glpi_currenttime"])
|
|
-strtotime($this->fields['password_forget_token_date'])) < DAY_TIMESTAMP)) {
|
|
|
|
$input['id'] = $this->fields['id'];
|
|
Config::validatePassword($input["password"], false); // Throws exception if password is invalid
|
|
if (!$this->update($input)) {
|
|
return false;
|
|
}
|
|
$input2 = [
|
|
'password_forget_token' => '',
|
|
'password_forget_token_date' => 'NULL',
|
|
'id' => $this->fields['id']
|
|
];
|
|
$this->update($input2);
|
|
return true;
|
|
|
|
} else {
|
|
throw new ForgetPasswordException(__('Your password reset request has expired or is invalid. Please renew it.'));
|
|
}
|
|
|
|
} else {
|
|
throw new ForgetPasswordException(__("The authentication method configuration doesn't allow you to change your password."));
|
|
}
|
|
|
|
} else {
|
|
throw new ForgetPasswordException(__('Email address not found.'));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* Displays password recovery result.
|
|
*
|
|
* @param array $input
|
|
*
|
|
* @return void
|
|
*/
|
|
public function showUpdateForgottenPassword(array $input) {
|
|
global $CFG_GLPI;
|
|
|
|
echo "<div class='center'>";
|
|
try {
|
|
if (!$this->updateForgottenPassword($input)) {
|
|
Html::displayMessageAfterRedirect();
|
|
} else {
|
|
echo __('Reset password successful.');
|
|
}
|
|
} catch (ForgetPasswordException $e) {
|
|
echo $e->getMessage();
|
|
} catch (PasswordTooWeakException $e) {
|
|
// Force display on error
|
|
foreach ($e->getMessages() as $message) {
|
|
Session::addMessageAfterRedirect($message);
|
|
}
|
|
Html::displayMessageAfterRedirect();
|
|
}
|
|
|
|
echo "<br>";
|
|
echo "<a href=\"".$CFG_GLPI['root_doc']."/index.php\">".__s('Back')."</a>";
|
|
echo "</div>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Send password recovery for a user and display result message.
|
|
*
|
|
* @param string $email email of the user
|
|
*
|
|
* @return void
|
|
*/
|
|
public function showForgetPassword($email) {
|
|
|
|
echo "<div class='center'>";
|
|
try {
|
|
$this->forgetPassword($email);
|
|
} catch (ForgetPasswordException $e) {
|
|
echo $e->getMessage();
|
|
return;
|
|
}
|
|
echo __('An email has been sent to your email address. The email contains information for reset your password.');
|
|
}
|
|
|
|
/**
|
|
* Send password recovery email for a user.
|
|
*
|
|
* @param string $email
|
|
*
|
|
* @throws ForgetPasswordException when requirements are not met
|
|
*
|
|
* @return boolean true if notification successfully created, false if user not found
|
|
*/
|
|
public function forgetPassword($email) {
|
|
$condition = [
|
|
'glpi_users.is_active' => 1,
|
|
'glpi_users.is_deleted' => 0, [
|
|
'OR' => [
|
|
['glpi_users.begin_date' => null],
|
|
['glpi_users.begin_date' => ['<', new QueryExpression('NOW()')]]
|
|
],
|
|
], [
|
|
'OR' => [
|
|
['glpi_users.end_date' => null],
|
|
['glpi_users.end_date' => ['>', new QueryExpression('NOW()')]]
|
|
]
|
|
]
|
|
];
|
|
|
|
if ($this->getFromDBbyEmail($email, $condition)) {
|
|
|
|
// Send token if auth DB or not external auth defined
|
|
if (($this->fields["authtype"] == Auth::DB_GLPI)
|
|
|| !Auth::useAuthExt()) {
|
|
|
|
if (NotificationMailing::isUserAddressValid($email)) {
|
|
$input = [
|
|
'password_forget_token' => sha1(Toolbox::getRandomString(30)),
|
|
'password_forget_token_date' => $_SESSION["glpi_currenttime"],
|
|
'id' => $this->fields['id'],
|
|
];
|
|
$this->update($input);
|
|
// Notication on root entity (glpi_users.entities_id is only a pref)
|
|
NotificationEvent::raiseEvent('passwordforget', $this, ['entities_id' => 0]);
|
|
QueuedNotification::forceSendFor($this->getType(), $this->fields['id']);
|
|
return true;
|
|
} else {
|
|
throw new ForgetPasswordException(__('Invalid email address'));
|
|
}
|
|
|
|
} else {
|
|
throw new ForgetPasswordException(__("The authentication method configuration doesn't allow you to change your password."));
|
|
}
|
|
|
|
}
|
|
|
|
throw new ForgetPasswordException(__('Email address not found.'));
|
|
}
|
|
|
|
|
|
/**
|
|
* Display information from LDAP server for user.
|
|
*
|
|
* @return void
|
|
*/
|
|
private function showLdapDebug() {
|
|
|
|
if ($this->fields['authtype'] != Auth::LDAP) {
|
|
return false;
|
|
}
|
|
echo "<div class='spaced'>";
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr><th colspan='4'>".AuthLDAP::getTypeName(1)."</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_2'><td>".__('User DN')."</td>";
|
|
echo "<td>".$this->fields['user_dn']."</td></tr>\n";
|
|
|
|
if ($this->fields['user_dn']) {
|
|
echo "<tr class='tab_bg_2'><td>".__('User information')."</td><td>";
|
|
$config_ldap = new AuthLDAP();
|
|
$ds = false;
|
|
|
|
if ($config_ldap->getFromDB($this->fields['auths_id'])) {
|
|
$ds = $config_ldap->connect();
|
|
}
|
|
|
|
if ($ds) {
|
|
$info = AuthLDAP::getUserByDn($ds, $this->fields['user_dn'],
|
|
['*', 'createTimeStamp', 'modifyTimestamp']);
|
|
if (is_array($info)) {
|
|
Html::printCleanArray($info);
|
|
} else {
|
|
echo __('No item to display');
|
|
}
|
|
|
|
} else {
|
|
echo __('Connection failed');
|
|
}
|
|
|
|
echo "</td></tr>\n";
|
|
}
|
|
|
|
echo "</table></div>";
|
|
}
|
|
|
|
|
|
/**
|
|
* Display debug information for current object.
|
|
*
|
|
* @return void
|
|
*/
|
|
function showDebug() {
|
|
|
|
NotificationEvent::debugEvent($this);
|
|
$this->showLdapDebug();
|
|
}
|
|
|
|
function getUnicityFieldsToDisplayInErrorMessage() {
|
|
|
|
return ['id' => __('ID'),
|
|
'entities_id' => Entity::getTypeName(1)];
|
|
}
|
|
|
|
|
|
function getUnallowedFieldsForUnicity() {
|
|
|
|
return array_merge(parent::getUnallowedFieldsForUnicity(),
|
|
['auths_id', 'date_sync', 'entities_id', 'last_login', 'profiles_id']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Get a unique generated token.
|
|
*
|
|
* @param string $field Field storing the token
|
|
*
|
|
* @return string
|
|
*/
|
|
static function getUniqueToken($field = 'personal_token') {
|
|
global $DB;
|
|
|
|
$ok = false;
|
|
do {
|
|
$key = Toolbox::getRandomString(40);
|
|
$row = $DB->request([
|
|
'COUNT' => 'cpt',
|
|
'FROM' => self::getTable(),
|
|
'WHERE' => [$field => $key]
|
|
])->next();
|
|
|
|
if ($row['cpt'] == 0) {
|
|
return $key;
|
|
}
|
|
} while (!$ok);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Get token of a user. If not exists generate it.
|
|
*
|
|
* @param integer $ID User ID
|
|
* @param string $field Field storing the token
|
|
*
|
|
* @return string|boolean User token, false if user does not exist
|
|
*/
|
|
static function getToken($ID, $field = 'personal_token') {
|
|
|
|
$user = new self();
|
|
if ($user->getFromDB($ID)) {
|
|
return $user->getAuthToken($field);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get token of a user. If it does not exists then generate it.
|
|
*
|
|
* @since 9.4
|
|
*
|
|
* @param string $field the field storing the token
|
|
* @param boolean $force_new force generation of a new token
|
|
*
|
|
* @return string|false token or false in case of error
|
|
*/
|
|
public function getAuthToken($field = 'personal_token', $force_new = false) {
|
|
global $CFG_GLPI;
|
|
|
|
if ($this->isNewItem()) {
|
|
return false;
|
|
}
|
|
|
|
// check date validity for cookie token
|
|
$outdated = false;
|
|
if ($field === 'cookie_token') {
|
|
$date_create = new DateTime($this->fields[$field."_date"]);
|
|
$date_expir = $date_create->add(new DateInterval('PT'.$CFG_GLPI["login_remember_time"].'S'));
|
|
|
|
if ($date_expir < new DateTime()) {
|
|
$outdated = true;
|
|
}
|
|
}
|
|
|
|
// token exists, is not oudated, and we may use it
|
|
if (!empty($this->fields[$field]) && !$force_new && !$outdated) {
|
|
return $this->fields[$field];
|
|
}
|
|
|
|
// else get a new token
|
|
$token = self::getUniqueToken($field);
|
|
|
|
// for cookie token, we need to store it hashed
|
|
$hash = $token;
|
|
if ($field === 'cookie_token') {
|
|
$hash = Auth::getPasswordHash($token);
|
|
}
|
|
|
|
// save this token in db
|
|
$this->update(['id' => $this->getID(),
|
|
$field => $hash,
|
|
$field . "_date" => $_SESSION['glpi_currenttime']]);
|
|
|
|
return $token;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get name of users using default passwords
|
|
*
|
|
* @return string[]
|
|
*/
|
|
static function checkDefaultPasswords() {
|
|
global $DB;
|
|
|
|
$passwords = ['glpi' => 'glpi',
|
|
'tech' => 'tech',
|
|
'normal' => 'normal',
|
|
'post-only' => 'postonly'];
|
|
$default_password_set = [];
|
|
|
|
$crit = ['FIELDS' => ['name', 'password'],
|
|
'is_active' => 1,
|
|
'is_deleted' => 0,
|
|
'name' => array_keys($passwords)];
|
|
|
|
foreach ($DB->request('glpi_users', $crit) as $data) {
|
|
if (Auth::checkPassword($passwords[$data['name']], $data['password'])) {
|
|
$default_password_set[] = $data['name'];
|
|
}
|
|
}
|
|
|
|
return $default_password_set;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get picture URL from picture field.
|
|
*
|
|
* @since 0.85
|
|
*
|
|
* @param string $picture Picture field value
|
|
*
|
|
* @return string
|
|
*/
|
|
static function getURLForPicture($picture) {
|
|
global $CFG_GLPI;
|
|
|
|
$url = Toolbox::getPictureUrl($picture);
|
|
if (null !== $url) {
|
|
return $url;
|
|
}
|
|
|
|
return $CFG_GLPI["root_doc"]."/pics/picture.png";
|
|
}
|
|
|
|
|
|
/**
|
|
* Get thumbnail URL from picture field.
|
|
*
|
|
* @since 0.85
|
|
*
|
|
* @param string $picture Picture field value
|
|
*
|
|
* @return string
|
|
*/
|
|
static function getThumbnailURLForPicture($picture) {
|
|
global $CFG_GLPI;
|
|
|
|
// prevent xss
|
|
$picture = Html::cleanInputText($picture);
|
|
|
|
if (!empty($picture)) {
|
|
$tmp = explode(".", $picture);
|
|
if (count($tmp) ==2) {
|
|
return $CFG_GLPI["root_doc"]."/front/document.send.php?file=_pictures/".$tmp[0].
|
|
"_min.".$tmp[1];
|
|
}
|
|
return $CFG_GLPI["root_doc"]."/pics/picture_min.png";
|
|
}
|
|
return $CFG_GLPI["root_doc"]."/pics/picture_min.png";
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Drop existing files for user picture.
|
|
*
|
|
* @since 0.85
|
|
*
|
|
* @param string $picture Picture field value
|
|
*
|
|
* @return void
|
|
*/
|
|
static function dropPictureFiles($picture) {
|
|
|
|
if (!empty($picture)) {
|
|
// unlink main file
|
|
if (file_exists(GLPI_PICTURE_DIR."/$picture")) {
|
|
@unlink(GLPI_PICTURE_DIR."/$picture");
|
|
}
|
|
// unlink Thunmnail
|
|
$tmp = explode(".", $picture);
|
|
if (count($tmp) == 2) {
|
|
if (file_exists(GLPI_PICTURE_DIR."/".$tmp[0]."_min.".$tmp[1])) {
|
|
@unlink(GLPI_PICTURE_DIR."/".$tmp[0]."_min.".$tmp[1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function getRights($interface = 'central') {
|
|
|
|
$values = parent::getRights();
|
|
//TRANS: short for : Add users from an external source
|
|
$values[self::IMPORTEXTAUTHUSERS] = ['short' => __('Add external'),
|
|
'long' => __('Add users from an external source')];
|
|
//TRANS: short for : Read method for user authentication and synchronization
|
|
$values[self::READAUTHENT] = ['short' => __('Read auth'),
|
|
'long' => __('Read user authentication and synchronization method')];
|
|
//TRANS: short for : Update method for user authentication and synchronization
|
|
$values[self::UPDATEAUTHENT] = ['short' => __('Update auth and sync'),
|
|
'long' => __('Update method for user authentication and synchronization')];
|
|
|
|
return $values;
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve the list of LDAP field names from a list of fields
|
|
* allow pattern substitution, e.g. %{name}.
|
|
*
|
|
* @since 9.1
|
|
*
|
|
* @param string[] $map array of fields
|
|
*
|
|
* @return string[]
|
|
*/
|
|
private static function getLdapFieldNames(array $map) {
|
|
|
|
$ret = [];
|
|
foreach ($map as $v) {
|
|
/** @var array $reg */
|
|
if (preg_match_all('/%{(.*)}/U', $v, $reg)) {
|
|
// e.g. "%{country} > %{city} > %{site}"
|
|
foreach ($reg [1] as $f) {
|
|
$ret [] = $f;
|
|
}
|
|
} else {
|
|
// single field name
|
|
$ret [] = $v;
|
|
}
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* Retrieve the value of a fields from a LDAP result applying needed substitution of %{value}.
|
|
*
|
|
* @since 9.1
|
|
*
|
|
* @param string $map String with field format
|
|
* @param array $res LDAP result
|
|
*
|
|
* @return string
|
|
*/
|
|
private static function getLdapFieldValue($map, array $res) {
|
|
|
|
$map = Toolbox::unclean_cross_side_scripting_deep($map);
|
|
$ret = preg_replace_callback('/%{(.*)}/U',
|
|
function ($matches) use ($res) {
|
|
return (isset($res[0][$matches[1]][0]) ? $res[0][$matches[1]][0] : '');
|
|
}, $map );
|
|
|
|
return $ret == $map ? (isset($res[0][$map][0]) ? $res[0][$map][0] : '') : $ret;
|
|
}
|
|
|
|
/**
|
|
* Get/Print the switch language form.
|
|
*
|
|
* @param boolean $display Whether to display or return output
|
|
* @param array $options Options
|
|
* - string value Selected language value
|
|
* - boolean showbutton Whether to display or not submit button
|
|
*
|
|
* @return void|string Nothing if displayed, string to display otherwise
|
|
*/
|
|
function showSwitchLangForm($display = true, array $options = []) {
|
|
|
|
$params = [
|
|
'value' => $_SESSION["glpilanguage"],
|
|
'display' => false,
|
|
'showbutton' => true
|
|
];
|
|
|
|
foreach ($options as $key => $value) {
|
|
$params[$key] = $value;
|
|
}
|
|
|
|
$out = '';
|
|
$out .= "<form method='post' name='switchlang' action='".User::getFormURL()."' autocomplete='off'>";
|
|
$out .= "<p class='center'>";
|
|
$out .= Dropdown::showLanguages("language", $params);
|
|
if ($params['showbutton'] === true) {
|
|
$out .= " <input type='submit' name='update' value=\""._sx('button', 'Save')."\" class='submit'>";
|
|
}
|
|
$out .= "</p>";
|
|
$out .= Html::closeForm(false);
|
|
|
|
if ($display === true) {
|
|
echo $out;
|
|
} else {
|
|
return $out;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get list of entities ids for current user.
|
|
*
|
|
* @return integer[]
|
|
*/
|
|
private function getEntities() {
|
|
//get user entities
|
|
if ($this->entities == null) {
|
|
$this->entities = Profile_User::getUserEntities($this->fields['id'], true);
|
|
}
|
|
return $this->entities;
|
|
}
|
|
|
|
|
|
/**
|
|
* Give cron information.
|
|
*
|
|
* @param string $name Task's name
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function cronInfo(string $name): array {
|
|
|
|
$info = [];
|
|
switch ($name) {
|
|
case 'passwordexpiration':
|
|
$info = [
|
|
'description' => __('Handle users passwords expiration policy'),
|
|
'parameter' => __('Maximum expiration notifications to send at once'),
|
|
];
|
|
break;
|
|
}
|
|
return $info;
|
|
}
|
|
|
|
/**
|
|
* Cron that notify users about when their password expire and deactivate their account
|
|
* depending on password expiration policy.
|
|
*
|
|
* @param CronTask $task
|
|
*
|
|
* @return integer
|
|
*/
|
|
public static function cronPasswordExpiration(CronTask $task) {
|
|
global $CFG_GLPI, $DB;
|
|
|
|
$expiration_delay = (int)$CFG_GLPI['password_expiration_delay'];
|
|
$notice_time = (int)$CFG_GLPI['password_expiration_notice'];
|
|
$notification_limit = (int)$task->fields['param'];
|
|
$lock_delay = (int)$CFG_GLPI['password_expiration_lock_delay'];
|
|
|
|
if (-1 === $expiration_delay || (-1 === $notice_time && -1 === $lock_delay)) {
|
|
// Nothing to do if passwords does not expire
|
|
// or if password expires without notice and with no lock delay
|
|
return 0;
|
|
}
|
|
|
|
// Notify users about expiration of their password.
|
|
$to_notify_count = 0;
|
|
if (-1 !== $notice_time) {
|
|
$notification_request = [
|
|
'FROM' => self::getTable(),
|
|
'LEFT JOIN' => [
|
|
Alert::getTable() => [
|
|
'ON' => [
|
|
Alert::getTable() => 'items_id',
|
|
self::getTable() => 'id',
|
|
[
|
|
'AND' => [
|
|
Alert::getTableField('itemtype') => self::getType(),
|
|
]
|
|
],
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
self::getTableField('is_deleted') => 0,
|
|
self::getTableField('is_active') => 1,
|
|
self::getTableField('authtype') => Auth::DB_GLPI,
|
|
new QueryExpression(
|
|
sprintf(
|
|
'NOW() > ADDDATE(%s, INTERVAL %s DAY)',
|
|
$DB->quoteName(self::getTableField('password_last_update')),
|
|
$expiration_delay - $notice_time
|
|
)
|
|
),
|
|
// Get only users that has not yet been notified within last day
|
|
'OR' => [
|
|
[Alert::getTableField('date') => null],
|
|
[Alert::getTableField('date') => ['<', new QueryExpression('CURRENT_TIMESTAMP() - INTERVAL 1 day')]],
|
|
],
|
|
],
|
|
];
|
|
|
|
$to_notify_count_request = array_merge(
|
|
$notification_request,
|
|
[
|
|
'COUNT' => 'cpt',
|
|
]
|
|
);
|
|
$to_notify_count = $DB->request($to_notify_count_request)->next()['cpt'];
|
|
|
|
$notification_data_request = array_merge(
|
|
$notification_request,
|
|
[
|
|
'SELECT' => [
|
|
self::getTableField('id as user_id'),
|
|
Alert::getTableField('id as alert_id'),
|
|
],
|
|
'LIMIT' => $notification_limit,
|
|
]
|
|
);
|
|
$notification_data_iterator = $DB->request($notification_data_request);
|
|
|
|
foreach ($notification_data_iterator as $notification_data) {
|
|
$user_id = $notification_data['user_id'];
|
|
$alert_id = $notification_data['alert_id'];
|
|
|
|
$user = new User();
|
|
$user->getFromDB($user_id);
|
|
|
|
$is_notification_send = NotificationEvent::raiseEvent(
|
|
'passwordexpires',
|
|
$user,
|
|
['entities_id' => 0] // Notication on root entity (glpi_users.entities_id is only a pref)
|
|
);
|
|
if (!$is_notification_send) {
|
|
continue;
|
|
}
|
|
|
|
$task->addVolume(1);
|
|
|
|
$alert = new Alert();
|
|
|
|
// Delete existing alert if any
|
|
if (null !== $alert_id) {
|
|
$alert->delete(['id' => $alert_id]);
|
|
}
|
|
|
|
// Add an alert to not warn user for at least one day
|
|
$alert->add(
|
|
[
|
|
'itemtype' => 'User',
|
|
'items_id' => $user_id,
|
|
'type' => Alert::NOTICE,
|
|
]
|
|
);
|
|
}
|
|
}
|
|
|
|
// Disable users if their password has expire for too long.
|
|
if (-1 !== $lock_delay) {
|
|
$DB->update(
|
|
self::getTable(),
|
|
[
|
|
'is_active' => 0,
|
|
'cookie_token' => null,
|
|
'cookie_token_date' => null,
|
|
],
|
|
[
|
|
'is_deleted' => 0,
|
|
'is_active' => 1,
|
|
'authtype' => Auth::DB_GLPI,
|
|
new QueryExpression(
|
|
sprintf(
|
|
'NOW() > ADDDATE(ADDDATE(%s, INTERVAL %d DAY), INTERVAL %s DAY)',
|
|
$DB->quoteName(self::getTableField('password_last_update')),
|
|
$expiration_delay,
|
|
$lock_delay
|
|
)
|
|
),
|
|
]
|
|
);
|
|
}
|
|
|
|
return -1 !== $notice_time && $to_notify_count > $notification_limit
|
|
? -1 // -1 for partial process (remaining notifications to send)
|
|
: 1; // 1 for fully process
|
|
}
|
|
|
|
/**
|
|
* Get password expiration time.
|
|
*
|
|
* @return null|int Password expiration time, or null if expiration mechanism is not active.
|
|
*/
|
|
public function getPasswordExpirationTime() {
|
|
global $CFG_GLPI;
|
|
|
|
if (!array_key_exists('id', $this->fields) || $this->fields['id'] < 1) {
|
|
return null;
|
|
}
|
|
|
|
$expiration_delay = (int)$CFG_GLPI['password_expiration_delay'];
|
|
|
|
if (-1 === $expiration_delay) {
|
|
return null;
|
|
}
|
|
|
|
return strtotime(
|
|
'+ ' . $expiration_delay . ' days',
|
|
strtotime($this->fields['password_last_update'])
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if password should be changed (if it expires soon).
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function shouldChangePassword() {
|
|
global $CFG_GLPI;
|
|
|
|
if ($this->hasPasswordExpired()) {
|
|
return true; // too late to change password, but returning false would not be logical here
|
|
}
|
|
|
|
$expiration_time = $this->getPasswordExpirationTime();
|
|
if (null === $expiration_time) {
|
|
return false;
|
|
}
|
|
|
|
$notice_delay = (int)$CFG_GLPI['password_expiration_notice'];
|
|
if (-1 === $notice_delay) {
|
|
return false;
|
|
}
|
|
|
|
$notice_time = strtotime('- ' . $notice_delay . ' days', $expiration_time);
|
|
|
|
return $notice_time < time();
|
|
}
|
|
|
|
/**
|
|
* Check if password expired.
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function hasPasswordExpired() {
|
|
|
|
$expiration_time = $this->getPasswordExpirationTime();
|
|
if (null === $expiration_time) {
|
|
return false;
|
|
}
|
|
|
|
return $expiration_time < time();
|
|
}
|
|
|
|
public static function getFriendlyNameSearchCriteria(string $filter): array {
|
|
$table = self::getTable();
|
|
$login = DBmysql::quoteName("$table.name");
|
|
$firstname = DBmysql::quoteName("$table.firstname");
|
|
$lastname = DBmysql::quoteName("$table.realname");
|
|
|
|
$filter = strtolower($filter);
|
|
$filter_no_spaces = str_replace(" ", "", $filter);
|
|
|
|
return [
|
|
'OR' => [
|
|
['RAW' => ["LOWER($login)" => ['LIKE', "%$filter%"]]],
|
|
['RAW' => ["LOWER(REPLACE(CONCAT($firstname, $lastname), ' ', ''))" => ['LIKE', "%$filter_no_spaces%"]]],
|
|
['RAW' => ["LOWER(REPLACE(CONCAT($lastname, $firstname), ' ', ''))" => ['LIKE', "%$filter_no_spaces%"]]],
|
|
]
|
|
];
|
|
}
|
|
|
|
public static function getFriendlyNameFields(string $alias = "name") {
|
|
$config = Config::getConfigurationValues('core');
|
|
if ($config['names_format'] == User::FIRSTNAME_BEFORE) {
|
|
$first = "firstname";
|
|
$second = "realname";
|
|
} else {
|
|
$first = "realname";
|
|
$second = "firstname";
|
|
}
|
|
|
|
$table = self::getTable();
|
|
$first = DB::quoteName("$table.$first");
|
|
$second = DB::quoteName("$table.$second");
|
|
$alias = DB::quoteName($alias);
|
|
$name = DB::quoteName(self::getNameField());
|
|
|
|
return new QueryExpression("IF(
|
|
$first <> '' && $second <> '',
|
|
CONCAT($first, ' ', $second),
|
|
$name
|
|
) AS $alias"
|
|
);
|
|
}
|
|
|
|
static function getIcon() {
|
|
return "fas fa-user";
|
|
}
|
|
|
|
/**
|
|
* Add groups stored in "_ldap_rules/groups_id" special input
|
|
*/
|
|
public function applyGroupsRules() {
|
|
if (!isset($this->input["_ldap_rules"]['groups_id'])) {
|
|
return;
|
|
}
|
|
|
|
$group_ids = array_unique($this->input["_ldap_rules"]['groups_id']);
|
|
foreach ($group_ids as $group_id) {
|
|
$group_user = new Group_User();
|
|
$group_user->add([
|
|
'groups_id' => $group_id,
|
|
'users_id' => $this->getId()
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
function displayPicklistSelected( $name ,$id_fonction = ''){
|
|
global $DB;
|
|
|
|
$result = $DB->query("select * from `picklist` WHERE `name` = '".$name."'");
|
|
$picklist_values = [] ;
|
|
|
|
while ($data = $DB->fetchAssoc($result)) {
|
|
$picklist_values[] = $data ;
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1'><td><label for=''>".$name."</label></td><td>
|
|
<select class='js-example-basic-single' style='width: 260px;' name='".strtolower($name)."'>
|
|
<option value=''>----</option>";
|
|
foreach ($picklist_values as $picklist_value) {
|
|
echo"<option value='".$picklist_value['id']."'"; if($id_fonction == $picklist_value['id']){ echo 'selected';} echo">".$picklist_value['value']."</option>";
|
|
}
|
|
|
|
echo "</select></td></tr><script>$(document).ready(function() { $('.js-example-basic-single').select2(); });</script>";
|
|
|
|
}
|
|
|
|
function displayPicklist($name){
|
|
global $DB;
|
|
|
|
$result = $DB->query("select * from `picklist` WHERE `name` = '".$name."'");
|
|
$picklist_values = [] ;
|
|
|
|
while ($data = $DB->fetchAssoc($result)) {
|
|
$picklist_values[] = $data ;
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1'><td><label for=''>".$name."</label></td><td>
|
|
<select class='js-example-basic-single' style='width: 260px;' name='".strtolower($name)."'>
|
|
<option value=''>----</option>";
|
|
foreach ($picklist_values as $picklist_value) {
|
|
echo"<option value='".$picklist_value['id']."'>".$picklist_value['value']."</option>";
|
|
}
|
|
|
|
echo "</select></td></tr><script>$(document).ready(function() { $('.js-example-basic-single').select2(); });</script>";
|
|
|
|
}
|
|
|
|
function displayPicklistSelectedUser($id){
|
|
global $DB;
|
|
|
|
$result = $DB->query("SELECT id,concat(realname ,' ',firstname) as fullname FROM `glpi_users`
|
|
WHERE is_deleted = 0 and ( realname is not null && firstname is not null)");
|
|
$picklist_values = [] ;
|
|
|
|
while ($data = $DB->fetchAssoc($result)) {
|
|
$picklist_values[] = $data ;
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1' style='display: none;'><td><label for=''>Responsable evaluation</label></td><td>
|
|
<select class='js-example-basic-single' style='width: 260px;' name='responsable_evaluation'>
|
|
<option value=''>----</option>";
|
|
foreach ($picklist_values as $picklist_value) {
|
|
echo"<option value='".$picklist_value['id']."'";
|
|
if($id == $picklist_value['id']){ echo 'selected';}
|
|
echo">".$picklist_value['fullname']."</option>";
|
|
}
|
|
|
|
echo "</select></td></tr><script>$(document).ready(function() { $('.js-example-basic-single').select2(); });</script>";
|
|
|
|
}
|
|
|
|
function displayPicklistUser(){
|
|
global $DB;
|
|
|
|
$result = $DB->query("SELECT id,concat(realname ,' ',firstname) as fullname FROM `glpi_users`
|
|
WHERE is_deleted = 0 and ( realname is not null && firstname is not null)");
|
|
$picklist_values = [] ;
|
|
|
|
while ($data = $DB->fetchAssoc($result)) {
|
|
$picklist_values[] = $data ;
|
|
}
|
|
|
|
echo "<tr class='tab_bg_1' style='display: none;'><td><label for=''>Responsable evaluation</label></td><td>
|
|
<select class='js-example-basic-single' style='width: 260px;' name='responsable_evaluation'>
|
|
<option value=''>----</option>";
|
|
foreach ($picklist_values as $picklist_value) {
|
|
echo"<option value='".$picklist_value['id']."'>".$picklist_value['fullname']."</option>";
|
|
}
|
|
|
|
echo "</select></td></tr><script>$(document).ready(function() { $('.js-example-basic-single').select2(); });</script>";
|
|
|
|
} |