From 7f850c29380a464638c4b83c64075a1c154b1cb3 Mon Sep 17 00:00:00 2001 From: Linty Date: Mon, 5 May 2025 20:24:05 +0200 Subject: [PATCH] issue #2354 update pwg.users.setInfo and add pwg.users.setMyInfo method --- include/functions_user.inc.php | 355 +++++++++++++++++++++++++++ include/ws_functions/pwg.users.php | 370 +++++++++-------------------- ws.php | 27 +++ 3 files changed, 493 insertions(+), 259 deletions(-) diff --git a/include/functions_user.inc.php b/include/functions_user.inc.php index 5ffe9d757..02e0a5fda 100644 --- a/include/functions_user.inc.php +++ b/include/functions_user.inc.php @@ -2028,4 +2028,359 @@ SELECT COUNT(*) } return true; } + +/** + * Check all user infos and save parameters + * + * @since 16 + * @param mixed[] $params + * @option string username (optional) + * @option string password (optional) + * @option string email (optional) + * @option string status (optional) + * @option int level (optional) + * @option string language (optional) + * @option string theme (optional) + * @option int nb_image_page (optional) + * @option int recent_period (optional) + * @option bool expand (optional) + * @option bool show_nb_comments (optional) + * @option bool show_nb_hits (optional) + * @option bool enabled_high (optional) + */ +function check_and_save_user_infos($params) +{ + if (isset($params['username']) and strlen(str_replace( " ", "", $params['username'])) == 0) + { + // return new PwgError(WS_ERR_INVALID_PARAM, 'Name field must not be empty'); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => 'Name field must not be empty' + ) + ); + } + + global $conf, $user, $service; + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + + $updates = $updates_infos = array(); + $update_status = null; + + if (count($params['user_id']) == 1) + { + if (get_username($params['user_id'][0]) === false) + { + // return new PwgError(WS_ERR_INVALID_PARAM, 'This user does not exist.'); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => 'This user does not exist.' + ) + ); + } + + if (!empty($params['username'])) + { + $user_id = get_userid($params['username']); + if ($user_id and $user_id != $params['user_id'][0]) + { + // return new PwgError(WS_ERR_INVALID_PARAM, l10n('this login is already used')); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => l10n('this login is already used') + ) + ); + } + if ($params['username'] != strip_tags($params['username'])) + { + // return new PwgError(WS_ERR_INVALID_PARAM, l10n('html tags are not allowed in login')); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => l10n('html tags are not allowed in login') + ) + ); + } + $updates[ $conf['user_fields']['username'] ] = $params['username']; + } + + if (!empty($params['email'])) + { + if ( ($error = validate_mail_address($params['user_id'][0], $params['email'])) != '') + { + // return new PwgError(WS_ERR_INVALID_PARAM, $error); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => $error + ) + ); + } + $updates[ $conf['user_fields']['email'] ] = $params['email']; + } + + if (!empty($params['password'])) + { + if (!is_webmaster()) + { + $password_protected_users = array($conf['guest_id']); + + $query = ' +SELECT + user_id + FROM '.USER_INFOS_TABLE.' + WHERE status IN (\'webmaster\', \'admin\') +;'; + $admin_ids = query2array($query, null, 'user_id'); + + // we add all admin+webmaster users BUT the user herself + $password_protected_users = array_merge($password_protected_users, array_diff($admin_ids, array($user['id']))); + + if (in_array($params['user_id'][0], $password_protected_users)) + { + // return new PwgError(403, 'Only webmasters can change password of other "webmaster/admin" users'); + return array( + 'error' => array( + 'code' => 403, + 'message' => 'Only webmasters can change password of other "webmaster/admin" users' + ) + ); + } + } + + $updates[ $conf['user_fields']['password'] ] = $conf['password_hash']($params['password']); + } + } + + if (!empty($params['status'])) + { + if (in_array($params['status'], array('webmaster', 'admin')) and !is_webmaster() ) + { + // return new PwgError(403, 'Only webmasters can grant "webmaster/admin" status'); + return array( + 'error' => array( + 'code '=> 403, + 'message' => 'Only webmasters can grant "webmaster/admin" status' + ) + ); + } + + if ( !in_array($params['status'], array('guest','generic','normal','admin','webmaster')) ) + { + // return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid status'); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => 'Invalid status' + ) + ); + } + + $protected_users = array( + $user['id'], + $conf['guest_id'], + $conf['webmaster_id'], + ); + + // an admin can't change status of other admin/webmaster + if ('admin' == $user['status']) + { + $query = ' +SELECT + user_id + FROM '.USER_INFOS_TABLE.' + WHERE status IN (\'webmaster\', \'admin\') +;'; + $protected_users = array_merge($protected_users, query2array($query, null, 'user_id')); + } + + // status update query is separated from the rest as not applying to the same + // set of users (current, guest and webmaster can't be changed) + $params['user_id_for_status'] = array_diff($params['user_id'], $protected_users); + + $update_status = $params['status']; + } + + if (!empty($params['level']) or @$params['level']===0) + { + if ( !in_array($params['level'], $conf['available_permission_levels']) ) + { + // return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid level'); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => 'Invalid level' + ) + ); + } + $updates_infos['level'] = $params['level']; + } + + if (!empty($params['language'])) + { + if ( !in_array($params['language'], array_keys(get_languages())) ) + { + // return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid language'); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => 'Invalid language' + ) + ); + } + $updates_infos['language'] = $params['language']; + } + + if (!empty($params['theme'])) + { + if ( !in_array($params['theme'], array_keys(get_pwg_themes())) ) + { + // return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid theme'); + return array( + 'error' => array( + 'code' => WS_ERR_INVALID_PARAM, + 'message' => 'Invalid theme' + ) + ); + } + $updates_infos['theme'] = $params['theme']; + } + + if (!empty($params['nb_image_page'])) + { + $updates_infos['nb_image_page'] = $params['nb_image_page']; + } + + if (!empty($params['recent_period']) or @$params['recent_period']===0) + { + $updates_infos['recent_period'] = $params['recent_period']; + } + + if (!empty($params['expand']) or @$params['expand']===false) + { + $updates_infos['expand'] = boolean_to_string($params['expand']); + } + + if (!empty($params['show_nb_comments']) or @$params['show_nb_comments']===false) + { + $updates_infos['show_nb_comments'] = boolean_to_string($params['show_nb_comments']); + } + + if (!empty($params['show_nb_hits']) or @$params['show_nb_hits']===false) + { + $updates_infos['show_nb_hits'] = boolean_to_string($params['show_nb_hits']); + } + + if (!empty($params['enabled_high']) or @$params['enabled_high']===false) + { + $updates_infos['enabled_high'] = boolean_to_string($params['enabled_high']); + } + + // perform updates + single_update( + USERS_TABLE, + $updates, + array($conf['user_fields']['id'] => $params['user_id'][0]) + ); + + if (isset($updates[ $conf['user_fields']['password'] ])) + { + deactivate_user_auth_keys($params['user_id'][0]); + } + + if (isset($updates[ $conf['user_fields']['email'] ])) + { + deactivate_password_reset_key($params['user_id'][0]); + } + + if (isset($update_status) and count($params['user_id_for_status']) > 0) + { + $query = ' +UPDATE '. USER_INFOS_TABLE .' SET + status = "'. $update_status .'" + WHERE user_id IN('. implode(',', $params['user_id_for_status']) .') +;'; + pwg_query($query); + + // we delete sessions, ie disconnect, for users if status becomes "guest". + // It's like deactivating the user. + if ('guest' == $update_status) + { + foreach ($params['user_id_for_status'] as $user_id_for_status) + { + delete_user_sessions($user_id_for_status); + } + } + } + + if (count($updates_infos) > 0) + { + $query = ' +UPDATE '. USER_INFOS_TABLE .' SET '; + + $first = true; + foreach ($updates_infos as $field => $value) + { + if (!$first) $query.= ', '; + else $first = false; + $query.= $field .' = "'. $value .'"'; + } + + $query.= ' + WHERE user_id IN('. implode(',', $params['user_id']) .') +;'; + pwg_query($query); + } + + // manage association to groups + if (!empty($params['group_id'])) + { + $query = ' +DELETE + FROM '.USER_GROUP_TABLE.' + WHERE user_id IN ('.implode(',', $params['user_id']).') +;'; + pwg_query($query); + + // we remove all provided groups that do not really exist + $query = ' +SELECT + id + FROM `'.GROUPS_TABLE.'` + WHERE id IN ('.implode(',', $params['group_id']).') +;'; + $group_ids = array_from_query($query, 'id'); + + // if only -1 (a group id that can't exist) is in the list, then no + // group is associated + + if (count($group_ids) > 0) + { + $inserts = array(); + + foreach ($group_ids as $group_id) + { + foreach ($params['user_id'] as $user_id) + { + $inserts[] = array('user_id' => $user_id, 'group_id' => $group_id); + } + } + + mass_inserts(USER_GROUP_TABLE, array_keys($inserts[0]), $inserts); + } + } + + invalidate_user_cache(); + + pwg_activity('user', $params['user_id'], 'edit'); + + return array( + 'user_id' => $params['user_id'], + 'infos' => $updates_infos, + 'account' => $updates + ); +} ?> diff --git a/include/ws_functions/pwg.users.php b/include/ws_functions/pwg.users.php index 65a7686f1..bb66f6baf 100644 --- a/include/ws_functions/pwg.users.php +++ b/include/ws_functions/pwg.users.php @@ -532,270 +532,122 @@ function ws_users_setInfo($params, &$service) return new PwgError(403, 'Invalid security token'); } - if (isset($params['username']) and strlen(str_replace( " ", "", $params['username'])) == 0) { - return new PwgError(WS_ERR_INVALID_PARAM, 'Name field must not be empty'); - } + $updated_users = check_and_save_user_infos($params); - global $conf, $user; - - include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); - - $updates = $updates_infos = array(); - $update_status = null; - - if (count($params['user_id']) == 1) + if (isset($updated_users['error'])) { - if (get_username($params['user_id'][0]) === false) - { - return new PwgError(WS_ERR_INVALID_PARAM, 'This user does not exist.'); - } - - if (!empty($params['username'])) - { - $user_id = get_userid($params['username']); - if ($user_id and $user_id != $params['user_id'][0]) - { - return new PwgError(WS_ERR_INVALID_PARAM, l10n('this login is already used')); - } - if ($params['username'] != strip_tags($params['username'])) - { - return new PwgError(WS_ERR_INVALID_PARAM, l10n('html tags are not allowed in login')); - } - $updates[ $conf['user_fields']['username'] ] = $params['username']; - } - - if (!empty($params['email'])) - { - if ( ($error = validate_mail_address($params['user_id'][0], $params['email'])) != '') - { - return new PwgError(WS_ERR_INVALID_PARAM, $error); - } - $updates[ $conf['user_fields']['email'] ] = $params['email']; - } - - if (!empty($params['password'])) - { - if (!is_webmaster()) - { - $password_protected_users = array($conf['guest_id']); - - $query = ' -SELECT - user_id - FROM '.USER_INFOS_TABLE.' - WHERE status IN (\'webmaster\', \'admin\') -;'; - $admin_ids = query2array($query, null, 'user_id'); - - // we add all admin+webmaster users BUT the user herself - $password_protected_users = array_merge($password_protected_users, array_diff($admin_ids, array($user['id']))); - - if (in_array($params['user_id'][0], $password_protected_users)) - { - return new PwgError(403, 'Only webmasters can change password of other "webmaster/admin" users'); - } - } - - $updates[ $conf['user_fields']['password'] ] = $conf['password_hash']($params['password']); - } + return new PwgError($updated_users[ 'error' ][ 'code' ], $updated_users[ 'error' ][ 'message' ]); } - if (!empty($params['status'])) - { - if (in_array($params['status'], array('webmaster', 'admin')) and !is_webmaster() ) - { - return new PwgError(403, 'Only webmasters can grant "webmaster/admin" status'); - } - - if ( !in_array($params['status'], array('guest','generic','normal','admin','webmaster')) ) - { - return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid status'); - } - - $protected_users = array( - $user['id'], - $conf['guest_id'], - $conf['webmaster_id'], - ); - - // an admin can't change status of other admin/webmaster - if ('admin' == $user['status']) - { - $query = ' -SELECT - user_id - FROM '.USER_INFOS_TABLE.' - WHERE status IN (\'webmaster\', \'admin\') -;'; - $protected_users = array_merge($protected_users, query2array($query, null, 'user_id')); - } - - // status update query is separated from the rest as not applying to the same - // set of users (current, guest and webmaster can't be changed) - $params['user_id_for_status'] = array_diff($params['user_id'], $protected_users); - - $update_status = $params['status']; - } - - if (!empty($params['level']) or @$params['level']===0) - { - if ( !in_array($params['level'], $conf['available_permission_levels']) ) - { - return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid level'); - } - $updates_infos['level'] = $params['level']; - } - - if (!empty($params['language'])) - { - if ( !in_array($params['language'], array_keys(get_languages())) ) - { - return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid language'); - } - $updates_infos['language'] = $params['language']; - } - - if (!empty($params['theme'])) - { - if ( !in_array($params['theme'], array_keys(get_pwg_themes())) ) - { - return new PwgError(WS_ERR_INVALID_PARAM, 'Invalid theme'); - } - $updates_infos['theme'] = $params['theme']; - } - - if (!empty($params['nb_image_page'])) - { - $updates_infos['nb_image_page'] = $params['nb_image_page']; - } - - if (!empty($params['recent_period']) or @$params['recent_period']===0) - { - $updates_infos['recent_period'] = $params['recent_period']; - } - - if (!empty($params['expand']) or @$params['expand']===false) - { - $updates_infos['expand'] = boolean_to_string($params['expand']); - } - - if (!empty($params['show_nb_comments']) or @$params['show_nb_comments']===false) - { - $updates_infos['show_nb_comments'] = boolean_to_string($params['show_nb_comments']); - } - - if (!empty($params['show_nb_hits']) or @$params['show_nb_hits']===false) - { - $updates_infos['show_nb_hits'] = boolean_to_string($params['show_nb_hits']); - } - - if (!empty($params['enabled_high']) or @$params['enabled_high']===false) - { - $updates_infos['enabled_high'] = boolean_to_string($params['enabled_high']); - } - - // perform updates - single_update( - USERS_TABLE, - $updates, - array($conf['user_fields']['id'] => $params['user_id'][0]) - ); - - if (isset($updates[ $conf['user_fields']['password'] ])) - { - deactivate_user_auth_keys($params['user_id'][0]); - } - - if (isset($updates[ $conf['user_fields']['email'] ])) - { - deactivate_password_reset_key($params['user_id'][0]); - } - - if (isset($update_status) and count($params['user_id_for_status']) > 0) - { - $query = ' -UPDATE '. USER_INFOS_TABLE .' SET - status = "'. $update_status .'" - WHERE user_id IN('. implode(',', $params['user_id_for_status']) .') -;'; - pwg_query($query); - - // we delete sessions, ie disconnect, for users if status becomes "guest". - // It's like deactivating the user. - if ('guest' == $update_status) - { - foreach ($params['user_id_for_status'] as $user_id_for_status) - { - delete_user_sessions($user_id_for_status); - } - } - } - - if (count($updates_infos) > 0) - { - $query = ' -UPDATE '. USER_INFOS_TABLE .' SET '; - - $first = true; - foreach ($updates_infos as $field => $value) - { - if (!$first) $query.= ', '; - else $first = false; - $query.= $field .' = "'. $value .'"'; - } - - $query.= ' - WHERE user_id IN('. implode(',', $params['user_id']) .') -;'; - pwg_query($query); - } - - // manage association to groups - if (!empty($params['group_id'])) - { - $query = ' -DELETE - FROM '.USER_GROUP_TABLE.' - WHERE user_id IN ('.implode(',', $params['user_id']).') -;'; - pwg_query($query); - - // we remove all provided groups that do not really exist - $query = ' -SELECT - id - FROM `'.GROUPS_TABLE.'` - WHERE id IN ('.implode(',', $params['group_id']).') -;'; - $group_ids = array_from_query($query, 'id'); - - // if only -1 (a group id that can't exist) is in the list, then no - // group is associated - - if (count($group_ids) > 0) - { - $inserts = array(); - - foreach ($group_ids as $group_id) - { - foreach ($params['user_id'] as $user_id) - { - $inserts[] = array('user_id' => $user_id, 'group_id' => $group_id); - } - } - - mass_inserts(USER_GROUP_TABLE, array_keys($inserts[0]), $inserts); - } - } - - invalidate_user_cache(); - - pwg_activity('user', $params['user_id'], 'edit'); - return $service->invoke('pwg.users.getList', array( - 'user_id' => $params['user_id'], - 'display' => 'basics,'.implode(',', array_keys($updates_infos)), - )); + 'user_id' => $updated_users['user_id'], + 'display' => 'basics,'.implode(',', array_keys($updated_users['infos'])), + )); +} + +/** + * API method + * Update user + * @since 16 + * @param mixed[] $params + * @option string email (optional) + * @option int nb_image_page (optional) + * @option string theme (optional) + * @option string language (optional) + * @option int recent_period (optional) + * @option bool expand (optional) + * @option bool show_nb_comments (optional) + * @option bool show_nb_hits (optional) + * @option string password (optional) + * @option string new_password (optional) + * @option string conf_new_password (optional) + */ +function ws_users_setMyInfo($params, &$service) +{ + if (get_pwg_token() != $params['pwg_token']) + { + return new PwgError(403, 'Invalid security token'); + } + + if (is_a_guest()) + { + return new PwgError(401, 'Access Denied'); + } + + global $user, $conf; + + // ACTIVATE_COMMENTS + if (!$conf['activate_comments']) + { + unset($params['show_nb_comments']); + } + + // ALLOW_USER_CUSTOMIZATION + if (!$conf['allow_user_customization']) + { + unset( + $params['nb_image_page'], + $params['theme'], + $params['language'], + $params['recent_period'], + $params['expand'], + $params['show_nb_comments'], + $params['show_nb_hits'] + ); + } + + // SPECIAL_USER + $special_user = in_array($user['id'], array($conf['guest_id'], $conf['default_user_id'])); + if ($special_user) + { + unset( + $params['password'], + $params['theme'], + $params['language'] + ); + } + + if (!empty($params['password'])) + { + if ($params['new_password'] != $params['conf_new_password']) + { + return new PwgError(403, l10n('The passwords do not match')); + } + + $query = ' +SELECT '.$conf['user_fields']['password'].' AS password + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['id'].' = \''.$user['id'].'\' +;'; + list($current_password) = pwg_db_fetch_row(pwg_query($query)); + + if (!$conf['password_verify']($params['password'], $current_password)) + { + return new PwgError(403, l10n('Current password is wrong')); + } + + $params['password'] = $params['new_password']; + } + + unset( + $params['new_password'], + $params['conf_new_password'], + $params['username'], + $params['status'], + $params['level'], + $params['group_id'], + $params['enabled_high'] + ); + + $params['user_id'] = [$user['id']]; + $updated_users = check_and_save_user_infos($params); + + if (isset($updated_users['error'])) + { + return new PwgError($updated_users[ 'error' ][ 'code' ], $updated_users[ 'error' ][ 'message' ]); + } + + return l10n('Your changes have been applied.'); } /** diff --git a/ws.php b/ws.php index c6c266a0d..337a0cc64 100644 --- a/ws.php +++ b/ws.php @@ -1238,6 +1238,33 @@ enabled_high, registration_date, registration_date_string, registration_date_sin $ws_functions_root . 'pwg.users.php', array('admin_only'=>true, 'post_only'=>true) ); + + $service->addMethod( + 'pwg.users.setMyInfo', + 'ws_users_setMyInfo', + array( + 'email' => array('flags'=>WS_PARAM_OPTIONAL), + 'nb_image_page' => array('flags'=>WS_PARAM_OPTIONAL, + 'type'=>WS_TYPE_INT|WS_TYPE_POSITIVE|WS_TYPE_NOTNULL), + 'theme' => array('flags'=>WS_PARAM_OPTIONAL), + 'language' => array('flags'=>WS_PARAM_OPTIONAL), + 'recent_period' => array('flags'=>WS_PARAM_OPTIONAL, + 'type'=>WS_TYPE_INT|WS_TYPE_POSITIVE), + 'expand' => array('flags'=>WS_PARAM_OPTIONAL, + 'type'=>WS_TYPE_BOOL), + 'show_nb_comments' => array('flags'=>WS_PARAM_OPTIONAL, + 'type'=>WS_TYPE_BOOL), + 'show_nb_hits' => array('flags'=>WS_PARAM_OPTIONAL, + 'type'=>WS_TYPE_BOOL), + 'password' => array('flags'=>WS_PARAM_OPTIONAL), + 'new_password' => array('flags'=>WS_PARAM_OPTIONAL), + 'conf_new_password' => array('flags'=>WS_PARAM_OPTIONAL), + 'pwg_token' => array(), + ), + '', + $ws_functions_root . 'pwg.users.php', + array('admin_only'=>false, 'post_only'=>true) + ); $service->addMethod( 'pwg.permissions.getList',