FINERACT-2185: User management improvement
This commit is contained in:
committed by
Adam Saghy
parent
8d83b5547c
commit
79c006774e
+1
-1
@@ -268,7 +268,7 @@ public class CenterImportHandler implements ImportHandler {
|
||||
String payload = gsonBuilder.create().toJson(calendarData);
|
||||
CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(),
|
||||
result.getLoanId(), result.getSavingsId(), null, null, null, null, null, payload, result.getTransactionId(),
|
||||
result.getProductId(), null, null, null, null, idempotencyKeyGenerator.create(), null);
|
||||
result.getProductId(), null, null, null, null, idempotencyKeyGenerator.create(), null, null);
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
.createCalendar(commandWrapper, TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) //
|
||||
.withJson(payload) //
|
||||
|
||||
+1
-1
@@ -252,7 +252,7 @@ public class GroupImportHandler implements ImportHandler {
|
||||
|
||||
CommandWrapper commandWrapper = new CommandWrapper(result.getOfficeId(), result.getGroupId(), result.getClientId(),
|
||||
result.getLoanId(), result.getSavingsId(), null, null, null, null, null, payload, result.getTransactionId(),
|
||||
result.getProductId(), null, null, null, null, idempotencyKeyGenerator.create(), null);
|
||||
result.getProductId(), null, null, null, null, idempotencyKeyGenerator.create(), null, null);
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
.createCalendar(commandWrapper, TemplatePopulateImportConstants.CENTER_ENTITY_TYPE, result.getGroupId()) //
|
||||
.withJson(payload) //
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public class InteropWrapperBuilder {
|
||||
|
||||
public CommandWrapper build() {
|
||||
return new CommandWrapper(null, null, null, null, null, actionName, entityName, null, null, href, json, null, null, null, null,
|
||||
null, null, null, null);
|
||||
null, null, null, null, null);
|
||||
}
|
||||
|
||||
public InteropWrapperBuilder withJson(final String json) {
|
||||
|
||||
+22
-1
@@ -171,7 +171,7 @@ public class UsersApiResource {
|
||||
|
||||
@PUT
|
||||
@Path("{userId}")
|
||||
@Operation(summary = "Update a User", description = "When updating a password you must provide the repeatPassword parameter also.")
|
||||
@Operation(summary = "Update a User", description = "Updates the user")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = UsersApiResourceSwagger.PutUsersUserIdRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = UsersApiResourceSwagger.PutUsersUserIdResponse.class))) })
|
||||
@@ -190,6 +190,27 @@ public class UsersApiResource {
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Path("{userId}/pwd")
|
||||
@Operation(summary = "Change the password of a User", description = "When updating a password you must provide the repeatPassword parameter also.")
|
||||
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = UsersApiResourceSwagger.ChangePwdUsersUserIdRequest.class)))
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = UsersApiResourceSwagger.ChangePwdUsersUserIdResponse.class))) })
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String changePassword(@PathParam("userId") @Parameter(description = "userId") final Long userId,
|
||||
@Parameter(hidden = true) final String apiRequestBodyAsJson) {
|
||||
|
||||
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
|
||||
.changeUserPassword(userId) //
|
||||
.withJson(apiRequestBodyAsJson) //
|
||||
.build();
|
||||
|
||||
final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
|
||||
|
||||
return this.toApiJsonSerializer.serialize(result);
|
||||
}
|
||||
|
||||
@DELETE
|
||||
@Path("{userId}")
|
||||
@Operation(summary = "Delete a User", description = "Removes the user and the associated roles and permissions.")
|
||||
|
||||
+37
@@ -151,6 +151,43 @@ final class UsersApiResourceSwagger {
|
||||
public Long resourceId;
|
||||
}
|
||||
|
||||
@Schema(description = "ChangePwdUsersUserIdRequest")
|
||||
public static final class ChangePwdUsersUserIdRequest {
|
||||
|
||||
private ChangePwdUsersUserIdRequest() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "password")
|
||||
public String password;
|
||||
@Schema(example = "repeatPassword")
|
||||
public String repeatPassword;
|
||||
}
|
||||
|
||||
@Schema(description = "ChangePwdUsersUserIdResponse")
|
||||
public static final class ChangePwdUsersUserIdResponse {
|
||||
|
||||
private ChangePwdUsersUserIdResponse() {
|
||||
|
||||
}
|
||||
|
||||
static final class ChangePwdUsersUserIdResponseChanges {
|
||||
|
||||
private ChangePwdUsersUserIdResponseChanges() {
|
||||
|
||||
}
|
||||
|
||||
@Schema(example = "true")
|
||||
public boolean password;
|
||||
}
|
||||
|
||||
@Schema(example = "1")
|
||||
public Long officeId;
|
||||
@Schema(example = "11")
|
||||
public Long resourceId;
|
||||
public ChangePwdUsersUserIdResponseChanges changes;
|
||||
}
|
||||
|
||||
@Schema(description = "PutUsersUserIdRequest")
|
||||
public static final class PutUsersUserIdRequest {
|
||||
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.fineract.useradministration.handler;
|
||||
|
||||
import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.useradministration.service.AppUserWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@CommandType(entity = "USER", action = "CHANGEPWD")
|
||||
public class ChangeUserPasswordCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final AppUserWritePlatformService writePlatformService;
|
||||
|
||||
@Autowired
|
||||
public ChangeUserPasswordCommandHandler(final AppUserWritePlatformService writePlatformService) {
|
||||
this.writePlatformService = writePlatformService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(final JsonCommand command) {
|
||||
final Long userId = command.entityId();
|
||||
return this.writePlatformService.changeUserPassword(userId, command);
|
||||
}
|
||||
}
|
||||
+2
@@ -25,6 +25,8 @@ public interface AppUserWritePlatformService {
|
||||
|
||||
CommandProcessingResult createUser(JsonCommand command);
|
||||
|
||||
CommandProcessingResult changeUserPassword(Long userId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult updateUser(Long userId, JsonCommand command);
|
||||
|
||||
CommandProcessingResult deleteUser(Long userId);
|
||||
|
||||
+30
@@ -154,6 +154,36 @@ public class AppUserWritePlatformServiceJpaRepositoryImpl implements AppUserWrit
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
||||
public CommandProcessingResult changeUserPassword(final Long userId, final JsonCommand command) {
|
||||
try {
|
||||
this.context.authenticatedUser(new CommandWrapperBuilder().updateUser(null).build());
|
||||
this.fromApiJsonDeserializer.validateForChangePassword(command.json(), this.context.authenticatedUser());
|
||||
final AppUser userToUpdate = this.appUserRepository.findById(userId).orElseThrow(() -> new UserNotFoundException(userId));
|
||||
final AppUserPreviousPassword currentPasswordToSaveAsPreview = getCurrentPasswordToSaveAsPreview(userToUpdate, command);
|
||||
final Map<String, Object> changes = userToUpdate.changePassword(command, this.platformPasswordEncoder);
|
||||
if (!changes.isEmpty()) {
|
||||
this.appUserRepository.saveAndFlush(userToUpdate);
|
||||
if (currentPasswordToSaveAsPreview != null) {
|
||||
this.appUserPreviewPasswordRepository.save(currentPasswordToSaveAsPreview);
|
||||
}
|
||||
}
|
||||
return new CommandProcessingResultBuilder() //
|
||||
.withEntityId(userId) //
|
||||
.withOfficeId(userToUpdate.getOffice().getId()) //
|
||||
.with(changes) //
|
||||
.build();
|
||||
} catch (final DataIntegrityViolationException dve) {
|
||||
throw handleDataIntegrityIssues(command, dve.getMostSpecificCause(), dve);
|
||||
} catch (final JpaSystemException | PersistenceException | AuthenticationServiceException dve) {
|
||||
log.error("changeUserPassword: JpaSystemException | PersistenceException | AuthenticationServiceException", dve);
|
||||
Throwable throwable = ExceptionUtils.getRootCause(dve.getCause());
|
||||
throw handleDataIntegrityIssues(command, throwable, dve);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
@Caching(evict = { @CacheEvict(value = "users", allEntries = true), @CacheEvict(value = "usersByUsername", allEntries = true) })
|
||||
|
||||
+46
-26
@@ -19,6 +19,8 @@
|
||||
package org.apache.fineract.useradministration.service;
|
||||
|
||||
import static org.apache.fineract.useradministration.service.AppUserConstants.CLIENTS;
|
||||
import static org.apache.fineract.useradministration.service.AppUserConstants.PASSWORD;
|
||||
import static org.apache.fineract.useradministration.service.AppUserConstants.REPEAT_PASSWORD;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
@@ -49,8 +51,6 @@ public final class UserDataValidator {
|
||||
public static final String USERNAME = "username";
|
||||
public static final String FIRSTNAME = "firstname";
|
||||
public static final String LASTNAME = "lastname";
|
||||
public static final String PASSWORD = "password";
|
||||
public static final String REPEAT_PASSWORD = "repeatPassword";
|
||||
public static final String EMAIL = "email";
|
||||
public static final String OFFICE_ID = "officeId";
|
||||
public static final String NOT_SELECTED_ROLES = "notSelectedRoles";
|
||||
@@ -61,9 +61,13 @@ public final class UserDataValidator {
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private static final Set<String> SUPPORTED_PARAMETERS = new HashSet<>(
|
||||
private static final Set<String> CREATE_SUPPORTED_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(USERNAME, FIRSTNAME, LASTNAME, PASSWORD, REPEAT_PASSWORD, EMAIL, OFFICE_ID, NOT_SELECTED_ROLES, ROLES,
|
||||
SEND_PASSWORD_TO_EMAIL, STAFF_ID, PASSWORD_NEVER_EXPIRES, AppUserConstants.IS_SELF_SERVICE_USER, CLIENTS));
|
||||
private static final Set<String> UPDATE_SUPPORTED_PARAMETERS = new HashSet<>(
|
||||
Arrays.asList(USERNAME, FIRSTNAME, LASTNAME, PASSWORD, REPEAT_PASSWORD, EMAIL, OFFICE_ID, NOT_SELECTED_ROLES, ROLES,
|
||||
SEND_PASSWORD_TO_EMAIL, STAFF_ID, PASSWORD_NEVER_EXPIRES, AppUserConstants.IS_SELF_SERVICE_USER, CLIENTS));
|
||||
private static final Set<String> CHANGE_PASSWORD_SUPPORTED_PARAMETERS = new HashSet<>(Arrays.asList(PASSWORD, REPEAT_PASSWORD));
|
||||
public static final String PASSWORD_NEVER_EXPIRE = "passwordNeverExpire";
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
@@ -84,7 +88,7 @@ public final class UserDataValidator {
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
|
||||
|
||||
}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, CREATE_SUPPORTED_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("user");
|
||||
@@ -106,16 +110,7 @@ public final class UserDataValidator {
|
||||
final String email = this.fromApiJsonHelper.extractStringNamed(EMAIL, element);
|
||||
baseDataValidator.reset().parameter(EMAIL).value(email).notBlank().notExceedingLengthOf(100);
|
||||
} else {
|
||||
final String password = this.fromApiJsonHelper.extractStringNamed(PASSWORD, element);
|
||||
final String repeatPassword = this.fromApiJsonHelper.extractStringNamed(REPEAT_PASSWORD, element);
|
||||
final PasswordValidationPolicy validationPolicy = this.passwordValidationPolicy.findActivePasswordValidationPolicy();
|
||||
final String regex = validationPolicy.getRegex();
|
||||
final String description = validationPolicy.getDescription();
|
||||
baseDataValidator.reset().parameter(PASSWORD).value(password).matchesRegularExpression(regex, description);
|
||||
|
||||
if (StringUtils.isNotBlank(password)) {
|
||||
baseDataValidator.reset().parameter(PASSWORD).value(password).equalToParameter(REPEAT_PASSWORD, repeatPassword);
|
||||
}
|
||||
validatePassword(baseDataValidator, element);
|
||||
}
|
||||
} else {
|
||||
baseDataValidator.reset().parameter(SEND_PASSWORD_TO_EMAIL).value(sendPasswordToEmail).trueOrFalseRequired(false);
|
||||
@@ -196,6 +191,27 @@ public final class UserDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
public void validateForChangePassword(final String json, AppUser authenticatedUser) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
}
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
|
||||
|
||||
}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, CHANGE_PASSWORD_SUPPORTED_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("user");
|
||||
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
validatePassword(baseDataValidator, element);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
validateFieldLevelACL(json, authenticatedUser);
|
||||
}
|
||||
|
||||
public void validateForUpdate(final String json, AppUser authenticatedUser) {
|
||||
if (StringUtils.isBlank(json)) {
|
||||
throw new InvalidJsonException();
|
||||
@@ -204,7 +220,7 @@ public final class UserDataValidator {
|
||||
final Type typeOfMap = new TypeToken<Map<String, Object>>() {
|
||||
|
||||
}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, SUPPORTED_PARAMETERS);
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, UPDATE_SUPPORTED_PARAMETERS);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("user");
|
||||
@@ -247,17 +263,7 @@ public final class UserDataValidator {
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(PASSWORD, element)) {
|
||||
final String password = this.fromApiJsonHelper.extractStringNamed(PASSWORD, element);
|
||||
final String repeatPassword = this.fromApiJsonHelper.extractStringNamed(REPEAT_PASSWORD, element);
|
||||
|
||||
final PasswordValidationPolicy validationPolicy = this.passwordValidationPolicy.findActivePasswordValidationPolicy();
|
||||
final String regex = validationPolicy.getRegex();
|
||||
final String description = validationPolicy.getDescription();
|
||||
baseDataValidator.reset().parameter(PASSWORD).value(password).matchesRegularExpression(regex, description);
|
||||
|
||||
if (StringUtils.isNotBlank(password)) {
|
||||
baseDataValidator.reset().parameter(PASSWORD).value(password).equalToParameter(REPEAT_PASSWORD, repeatPassword);
|
||||
}
|
||||
validatePassword(baseDataValidator, element);
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(PASSWORD_NEVER_EXPIRE, element)) {
|
||||
@@ -291,4 +297,18 @@ public final class UserDataValidator {
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
validateFieldLevelACL(json, authenticatedUser);
|
||||
}
|
||||
|
||||
private void validatePassword(DataValidatorBuilder baseDataValidator, JsonElement element) {
|
||||
final String password = this.fromApiJsonHelper.extractStringNamed(PASSWORD, element);
|
||||
final String repeatPassword = this.fromApiJsonHelper.extractStringNamed(REPEAT_PASSWORD, element);
|
||||
|
||||
final PasswordValidationPolicy validationPolicy = this.passwordValidationPolicy.findActivePasswordValidationPolicy();
|
||||
final String regex = validationPolicy.getRegex();
|
||||
final String description = validationPolicy.getDescription();
|
||||
DataValidatorBuilder validator = baseDataValidator.reset().parameter(PASSWORD).value(password).matchesRegularExpression(regex,
|
||||
description);
|
||||
if (StringUtils.isNotBlank(password)) {
|
||||
validator.equalToParameter(REPEAT_PASSWORD, repeatPassword);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,4 +191,5 @@
|
||||
<include file="parts/0170_days_in_year_custom_strategy.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0171_loan_capitalized_income.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0172_create_loan_capitalized_income_balance.xml" relativeToChangelogFile="true"/>
|
||||
<include file="parts/0173_user_change_pwd.xml" relativeToChangelogFile="true" />
|
||||
</databaseChangeLog>
|
||||
|
||||
+9
@@ -89,4 +89,13 @@
|
||||
<column name="can_maker_checker" valueBoolean="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="3">
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="portfolio"/>
|
||||
<column name="code" value="DEACTIVATEOVERDUE_LOANCHARGE"/>
|
||||
<column name="entity_name" value="LOANCHARGE"/>
|
||||
<column name="action_name" value="DEACTIVATEOVERDUE"/>
|
||||
<column name="can_maker_checker" valueBoolean="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
-->
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||
<changeSet author="fineract" id="1">
|
||||
<addColumn tableName="m_portfolio_command_source">
|
||||
<column name="is_sanitized" type="boolean" defaultValueBoolean="false" >
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</addColumn>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="2">
|
||||
<insert tableName="m_permission">
|
||||
<column name="grouping" value="authorisation"/>
|
||||
<column name="code" value="CHANGEPWD_USER"/>
|
||||
<column name="entity_name" value="USER"/>
|
||||
<column name="action_name" value="CHANGEPWD"/>
|
||||
<column name="can_maker_checker" valueBoolean="false"/>
|
||||
</insert>
|
||||
</changeSet>
|
||||
<changeSet author="fineract" id="3">
|
||||
<sql>
|
||||
INSERT INTO m_role_permission (role_id, permission_id)
|
||||
SELECT mrp.role_id, mp_changepwd.id
|
||||
FROM m_role_permission mrp
|
||||
LEFT JOIN m_permission mp_update ON mp_update.id = mrp.permission_id
|
||||
LEFT JOIN m_permission mp_changepwd ON mp_changepwd.action_name = 'CHANGEPWD'
|
||||
AND mp_changepwd.entity_name = 'USER'
|
||||
WHERE mp_update.action_name = 'UPDATE'
|
||||
AND mp_update.entity_name = 'USER';
|
||||
</sql>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@@ -39423,6 +39423,40 @@ Request body:
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="users_changepwd" name="users_changepwd" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Change the password of a User</h4>
|
||||
<p>
|
||||
<b>Note:</b> When updating a password you must provide the
|
||||
repeatPassword parameter also.
|
||||
</p>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
POST https://DomainName/api/v1/users/{userId)/pwd
|
||||
</code>
|
||||
<code class="method-request">
|
||||
POST users/3/pwd
|
||||
Content-Type: application/json
|
||||
Request body:
|
||||
{
|
||||
"password": "window75",
|
||||
"repeatPassword": "window75"
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"officeId": 1,
|
||||
"resourceId": 3,
|
||||
"changes": {
|
||||
"passwordEncoded": "abc3326b1bb376351c7baeb4175f5e0504e33aadf6a158474a6d71de1befae51"
|
||||
}
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a id="users_update" name="users_update" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
@@ -39451,8 +39485,7 @@ Request body:
|
||||
"officeId": 1,
|
||||
"resourceId": 3,
|
||||
"changes": {
|
||||
"firstname": "Test",
|
||||
"passwordEncoded": "abc3326b1bb376351c7baeb4175f5e0504e33aadf6a158474a6d71de1befae51"
|
||||
"firstname": "Test"
|
||||
}
|
||||
}
|
||||
</code>
|
||||
|
||||
+1
-1
@@ -101,7 +101,7 @@ public class CommandServiceStepDefinitions implements En {
|
||||
|
||||
public DummyCommand() {
|
||||
super(null, null, null, null, null, null, null, null, null, null, "{}", null, null, null, null, null, null,
|
||||
UUID.randomUUID().toString(), null);
|
||||
UUID.randomUUID().toString(), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
@@ -29,6 +29,7 @@ import org.apache.fineract.commands.domain.CommandSource;
|
||||
import org.apache.fineract.commands.domain.CommandSourceRepository;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.infrastructure.codes.exception.CodeNotFoundException;
|
||||
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
|
||||
import org.apache.fineract.infrastructure.core.exception.ErrorHandler;
|
||||
@@ -48,6 +49,9 @@ import org.mockito.MockitoAnnotations;
|
||||
@SuppressFBWarnings(value = "RV_EXCEPTION_NOT_THROWN", justification = "False positive")
|
||||
public class CommandSourceServiceTest {
|
||||
|
||||
@Mock
|
||||
private ConfigurationDomainService configurationDomainService;
|
||||
|
||||
@Mock
|
||||
private CommandSourceRepository commandSourceRepository;
|
||||
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ public class IdempotencyKeyResolverTest {
|
||||
public void testIPKResolveFromWrapper() {
|
||||
String idk = "idk";
|
||||
CommandWrapper wrapper = new CommandWrapper(null, null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
null, null, null, idk, null);
|
||||
null, null, null, idk, null, null);
|
||||
String resolvedIdk = underTest.resolve(wrapper);
|
||||
Assertions.assertEquals(idk, resolvedIdk);
|
||||
}
|
||||
|
||||
+2
-3
@@ -117,7 +117,7 @@ public class SynchronousCommandProcessingServiceTest {
|
||||
when(commandSource.getStatus()).thenReturn(CommandProcessingResultType.PROCESSED.getValue());
|
||||
when(context.authenticatedUser(Mockito.any(CommandWrapper.class))).thenReturn(appUser);
|
||||
|
||||
when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false, false))
|
||||
when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false))
|
||||
.thenReturn(commandProcessingResult);
|
||||
|
||||
CommandProcessingResult actualCommandProcessingResult = underTest.executeCommand(commandWrapper, jsonCommand, false);
|
||||
@@ -163,8 +163,7 @@ public class SynchronousCommandProcessingServiceTest {
|
||||
|
||||
when(commandSourceService.findCommandSource(commandWrapper, idk)).thenReturn(initialCommandSource);
|
||||
|
||||
when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false, false))
|
||||
.thenThrow(runtimeException);
|
||||
when(commandSourceService.processCommand(commandHandler, jsonCommand, commandSource, appUser, false)).thenThrow(runtimeException);
|
||||
|
||||
assertThrows(RuntimeException.class, () -> {
|
||||
underTest.executeCommand(commandWrapper, jsonCommand, false);
|
||||
|
||||
Reference in New Issue
Block a user