diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java index d0058cee2e6..e6cdcd0ff7a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java @@ -365,6 +365,15 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_MEETING") .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/*/*/meeting/*")) .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_MEETING") + // hook + .requestMatchers(API_MATCHER.matcher(HttpMethod.GET, "/api/*/hooks/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_READ, "READ_HOOK") + .requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/hooks/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "CREATE_HOOK") + .requestMatchers(API_MATCHER.matcher(HttpMethod.PUT, "/api/*/hooks/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "UPDATE_HOOK") + .requestMatchers(API_MATCHER.matcher(HttpMethod.DELETE, "/api/*/hooks/*")) + .hasAnyAuthority(ALL_FUNCTIONS, ALL_FUNCTIONS_WRITE, "DELETE_HOOK") .requestMatchers(API_MATCHER.matcher(HttpMethod.POST, "/api/*/twofactor/validate")).fullyAuthenticated() .requestMatchers(API_MATCHER.matcher("/api/*/twofactor")).fullyAuthenticated() diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiConstants.java index b1dcfe7db68..681e8b91861 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiConstants.java @@ -18,22 +18,10 @@ */ package org.apache.fineract.infrastructure.hooks.api; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - public final class HookApiConstants { private HookApiConstants() {} - public static final String HOOK_RESOURCE_NAME = "HOOK"; - - public static final String nameParamName = "name"; - - public static final String displayNameParamName = "displayName"; - - public static final String isActiveParamName = "isActive"; - public static final String webTemplateName = "Web"; public static final String elasticSearchTemplateName = "Elastic Search"; @@ -56,24 +44,5 @@ private HookApiConstants() {} public static final String apiKeyName = "Api Key"; - public static final String configParamName = "config"; - - public static final String eventsParamName = "events"; - - public static final String entityNameParamName = "entityName"; - - public static final String actionNameParamName = "actionName"; - - public static final String templateIdParamName = "templateId"; - - public static final String templateNameParamName = "templateName"; - public static final String SMSProviderIdParamName = "SMS Provider Id"; - - public static final Set RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(nameParamName, displayNameParamName, - templateIdParamName, isActiveParamName, configParamName, eventsParamName, templateNameParamName)); - - public static final Set UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(nameParamName, displayNameParamName, - templateIdParamName, isActiveParamName, configParamName, eventsParamName, templateNameParamName)); - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiResource.java index 57ee84ef5de..c851efa4fbc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiResource.java @@ -18,149 +18,123 @@ */ package org.apache.fineract.infrastructure.hooks.api; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.HOOK_RESOURCE_NAME; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.RESPONSE_DATA_PARAMETERS; +import static java.util.Objects.requireNonNull; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.ArraySchema; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.parameters.RequestBody; -import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.PUT; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.UriInfo; import java.util.Collection; +import java.util.function.Supplier; import lombok.RequiredArgsConstructor; -import org.apache.fineract.commands.domain.CommandWrapper; -import org.apache.fineract.commands.service.CommandWrapperBuilder; -import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; -import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; -import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer; +import org.apache.fineract.command.core.CommandDispatcher; +import org.apache.fineract.infrastructure.hooks.command.HookCreateCommand; +import org.apache.fineract.infrastructure.hooks.command.HookDeleteCommand; +import org.apache.fineract.infrastructure.hooks.command.HookUpdateCommand; +import org.apache.fineract.infrastructure.hooks.data.HookCreateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookCreateResponse; import org.apache.fineract.infrastructure.hooks.data.HookData; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteRequest; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteResponse; +import org.apache.fineract.infrastructure.hooks.data.HookDetailsData; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateResponse; import org.apache.fineract.infrastructure.hooks.service.HookReadPlatformService; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.springframework.stereotype.Component; @Path("/v1/hooks") +@Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Component @Tag(name = "Hooks", description = "Hooks are a mechanism to trigger custom code on the occurence of events. ") @RequiredArgsConstructor public class HookApiResource { - private final PlatformSecurityContext context; private final HookReadPlatformService readPlatformService; - private final DefaultToApiJsonSerializer toApiJsonSerializer; - private final ApiRequestParameterHelper apiRequestParameterHelper; - private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + private final CommandDispatcher dispatcher; @GET - @Operation(summary = "Retrieve Hooks", description = "Returns the list of hooks.\n" + "\n" + "Example Requests:\n" + "\n" + "hooks") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = HookApiResourceSwagger.GetHookResponse.class)))) - public String retrieveHooks(@Context final UriInfo uriInfo) { - - this.context.authenticatedUser().validateHasReadPermission(HOOK_RESOURCE_NAME); - - final Collection hooks = this.readPlatformService.retrieveAllHooks(); - - final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return this.toApiJsonSerializer.serialize(settings, hooks, RESPONSE_DATA_PARAMETERS); + @Operation(summary = "Retrieve Hooks", description = "Returns the list of hooks") + public Collection retrieveHooks(@Context final UriInfo uriInfo) { + return readPlatformService.retrieveAllHooks(); } @GET @Path("{hookId}") - @Operation(summary = "Retrieve a Hook", description = "Returns the details of a Hook.\n" + "\n" + "Example Requests:\n" + "\n" - + "hooks/1") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = HookApiResourceSwagger.GetHookResponse.class))) - public String retrieveHook(@PathParam("hookId") @Parameter(description = "hookId") final Long hookId, @Context final UriInfo uriInfo) { - - this.context.authenticatedUser().validateHasReadPermission(HOOK_RESOURCE_NAME); + @Operation(summary = "Retrieve a Hook", description = "Returns the details of a Hook.") + public HookData retrieveHook(@PathParam("hookId") @Parameter(description = "hookId") final Long hookId, + @QueryParam("template") @DefaultValue("false") @Parameter(description = "template") Boolean template) { + var hook = readPlatformService.retrieveHook(hookId); - final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + if (Boolean.TRUE.equals(template)) { + var hookTemplate = readPlatformService.retrieveNewHookDetails(hook.getTemplateName()); - HookData hook = this.readPlatformService.retrieveHook(hookId); - - if (settings.isTemplate()) { - final HookData hookData = this.readPlatformService.retrieveNewHookDetails(hook.getTemplateName()); - hook = HookData.templateExisting(hook, hookData.getTemplates(), hookData.getGroupings()); + hook.setTemplates(hookTemplate.getTemplates()); + hook.setGroupings(hookTemplate.getGroupings()); } - return this.toApiJsonSerializer.serialize(settings, hook, RESPONSE_DATA_PARAMETERS); + + return hook; } @GET @Path("template") - @Operation(summary = "Retrieve Hooks Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for client applications. The template data returned consists of any or all of:\n" - + "\n" + "Field Defaults\n" + "Allowed description Lists\n" + "Example Request:\n" + "\n" + "hooks/template") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = HookApiResourceSwagger.GetHookTemplateResponse.class))) - public String template(@Context final UriInfo uriInfo) { - - this.context.authenticatedUser().validateHasReadPermission(HOOK_RESOURCE_NAME); - - final HookData hook = this.readPlatformService.retrieveNewHookDetails(null); - - final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); - return this.toApiJsonSerializer.serialize(settings, hook, RESPONSE_DATA_PARAMETERS); + @Operation(summary = "Retrieve Hooks Template", description = "This is a convenience resource. It can be useful when building maintenance user interface screens for client applications.") + public HookDetailsData template() { + return readPlatformService.retrieveNewHookDetails(null); } @POST - @Consumes({ MediaType.APPLICATION_JSON }) - @Operation(summary = "Create a Hook", description = "The following parameters can be passed for the creation of a hook :-\n" + "\n" - + "name - string - Required. The name of the template that is being called. (See /hooks/template for the list of valid hook names.)\n" - + "\n" + "isActive - boolean - Determines whether the hook is actually triggered.\n" + "\n" - + "events - array - Determines what events the hook is triggered for.\n" + "\n" - + "config - hash - Required. Key/value pairs to provide settings for this hook. These settings vary between the templates.\n" - + "\n" + "templateId - Optional. The UGD template ID associated with the same entity (client or loan).") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = HookApiResourceSwagger.PostHookRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = HookApiResourceSwagger.PostHookResponse.class))) - public String createHook(@Parameter(hidden = true) final String apiRequestBodyAsJson) { - - final CommandWrapper commandRequest = new CommandWrapperBuilder().createHook().withJson(apiRequestBodyAsJson).build(); - - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - - return this.toApiJsonSerializer.serialize(result); + @Operation(summary = "Create a Hook", description = "") + public HookCreateResponse createHook(@Valid final HookCreateRequest request) { + final var command = new HookCreateCommand(); + command.setPayload(request); + + final Supplier response = dispatcher.dispatch(command); + + return response.get(); } @PUT @Path("{hookId}") - @Consumes({ MediaType.APPLICATION_JSON }) @Operation(summary = "Update a Hook", description = "Updates the details of a hook.") - @RequestBody(required = true, content = @Content(schema = @Schema(implementation = HookApiResourceSwagger.PutHookRequest.class))) - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = HookApiResourceSwagger.PutHookResponse.class))) - public String updateHook(@PathParam("hookId") @Parameter(description = "hookId") final Long hookId, - @Parameter(hidden = true) final String apiRequestBodyAsJson) { + public HookUpdateResponse updateHook(@PathParam("hookId") @Parameter(description = "hookId") final Long hookId, + @Valid HookUpdateRequest request) { + requireNonNull(hookId, "hookId is required"); + + request.setId(hookId); - final CommandWrapper commandRequest = new CommandWrapperBuilder().updateHook(hookId).withJson(apiRequestBodyAsJson).build(); + final var command = new HookUpdateCommand(); + command.setPayload(request); - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + final Supplier response = dispatcher.dispatch(command); - return this.toApiJsonSerializer.serialize(result); + return response.get(); } @DELETE @Path("{hookId}") @Operation(summary = "Delete a Hook", description = "Deletes a hook.") - @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = HookApiResourceSwagger.DeleteHookResponse.class))) - public String deleteHook(@PathParam("hookId") @Parameter(description = "hookId") final Long hookId) { + public HookDeleteResponse deleteHook(@PathParam("hookId") @Parameter(description = "hookId") final Long hookId) { + var request = HookDeleteRequest.builder().id(hookId).build(); - final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteHook(hookId).build(); + final var command = new HookDeleteCommand(); + command.setPayload(request); - final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + final Supplier response = dispatcher.dispatch(command); - return this.toApiJsonSerializer.serialize(result); + return response.get(); } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiResourceSwagger.java deleted file mode 100644 index 99f37e2d480..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/api/HookApiResourceSwagger.java +++ /dev/null @@ -1,159 +0,0 @@ -/** - * 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.infrastructure.hooks.api; - -import io.swagger.v3.oas.annotations.media.Schema; -import java.time.LocalDate; -import java.util.List; -import org.apache.fineract.infrastructure.hooks.data.Event; -import org.apache.fineract.infrastructure.hooks.data.Field; -import org.apache.fineract.infrastructure.hooks.data.Grouping; -import org.apache.fineract.infrastructure.hooks.data.HookTemplateData; - -/** - * Created by sanyam on 11/8/17. - */ - -final class HookApiResourceSwagger { - - private HookApiResourceSwagger() { - - } - - @Schema(description = "PostHookRequest") - public static final class PostHookRequest { - - private PostHookRequest() { - - } - - @Schema(example = "Web") - public String name; - @Schema(example = "true") - public Boolean isActive; - @Schema(example = "Kremlin") - public String displayName; - @Schema(example = "1") - public Long templateId; - public List events; - public List config; - } - - @Schema(description = "PostHookResponse") - public static final class PostHookResponse { - - private PostHookResponse() { - - } - - @Schema(example = "4") - public Long resourceId; - } - - @Schema(description = "GetHookResponse") - public static final class GetHookResponse { - - private GetHookResponse() { - - } - - @Schema(example = "1") - public Long id; - @Schema(example = "Web") - public String name; - @Schema(example = "Kremlin") - public String displayName; - @Schema(example = "true") - public Boolean isActive; - @Schema(example = "[2014, 9, 16]") - public LocalDate createdAt; - @Schema(example = "[2014, 9, 16]") - public LocalDate updatedAt; - @Schema(example = "1") - public Long templateId; - @Schema(example = "My UGD") - public String templateName; - public List events; - public List config; - } - - @Schema(description = "GetHookTemplateResponse") - public static final class GetHookTemplateResponse { - - private GetHookTemplateResponse() { - - } - - public List templates; - public List groupings; - } - - @Schema(description = "DeleteHookResponse") - public static final class DeleteHookResponse { - - private DeleteHookResponse() { - - } - - @Schema(example = "4") - public Long resourceId; - } - - @Schema(description = "PutHookRequest") - public static final class PutHookRequest { - - private PutHookRequest() { - - } - - @Schema(example = "Web") - public String name; - @Schema(example = "true") - public Boolean isActive; - @Schema(example = "Kremlin") - public String displayName; - @Schema(example = "1") - public Long templateId; - public List events; - public List config; - } - - @Schema(description = "PutHookResponse") - public static final class PutHookResponse { - - private PutHookResponse() { - - } - - static final class PutHookResponseChangesSwagger { - - private PutHookResponseChangesSwagger() {} - - @Schema(example = "Kremlin") - public String displayName; - @Schema(example = "1") - public List events; - public List config; - } - - @Schema(example = "4") - public Long resourceId; - public PutHookResponseChangesSwagger changes; - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookCreateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookCreateCommand.java new file mode 100644 index 00000000000..a7c50a88cf8 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookCreateCommand.java @@ -0,0 +1,28 @@ +/** + * 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.infrastructure.hooks.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.infrastructure.hooks.data.HookCreateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HookCreateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookDeleteCommand.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookDeleteCommand.java new file mode 100644 index 00000000000..fe3ce311d9a --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookDeleteCommand.java @@ -0,0 +1,28 @@ +/** + * 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.infrastructure.hooks.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HookDeleteCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookUpdateCommand.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookUpdateCommand.java new file mode 100644 index 00000000000..762135f777f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/command/HookUpdateCommand.java @@ -0,0 +1,28 @@ +/** + * 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.infrastructure.hooks.command; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateRequest; + +@Data +@EqualsAndHashCode(callSuper = true) +public class HookUpdateCommand extends Command {} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookCreateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookCreateRequest.java new file mode 100644 index 00000000000..24dd25ce286 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookCreateRequest.java @@ -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.infrastructure.hooks.data; + +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HookCreateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Size(max = 100, message = "{org.apache.fineract.infrastructure.hooks.name.size}") + private String name; + private Boolean isActive; + private String displayName; + private Long templateId; + private List events; + private Map config; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookCreateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookCreateResponse.java new file mode 100644 index 00000000000..acc6296598d --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookCreateResponse.java @@ -0,0 +1,38 @@ +/** + * 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.infrastructure.hooks.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HookCreateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookData.java index 056602d3d23..a2f36231bab 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookData.java @@ -18,19 +18,26 @@ */ package org.apache.fineract.infrastructure.hooks.data; +import java.io.Serial; import java.io.Serializable; import java.time.LocalDate; import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +@Builder @Data @NoArgsConstructor +@AllArgsConstructor @Accessors(chain = true) public final class HookData implements Serializable { + @Serial private static final long serialVersionUID = 1L; + private Long id; private String name; private String displayName; @@ -39,32 +46,8 @@ public final class HookData implements Serializable { private LocalDate updatedAt; private Long templateId; private String templateName; - - // associations - private List events; - private List config; - - // template data + private List events; + private List config; private List templates; - private List groupings; - - public static HookData instance(final Long id, final String name, final String displayName, final boolean isActive, - final LocalDate createdAt, final LocalDate updatedAt, final Long templateId, final List registeredEvents, - final List config, final String templateName) { - return new HookData().setId(id).setName(name).setDisplayName(displayName).setIsActive(isActive).setCreatedAt(createdAt) - .setUpdatedAt(updatedAt).setTemplateId(templateId).setTemplateName(templateName).setEvents(registeredEvents) - .setConfig(config); - } - - public static HookData template(final List templates, final List groupings) { - return new HookData().setTemplates(templates).setGroupings(groupings); - } - - public static HookData templateExisting(final HookData hookData, final List templates, - final List groupings) { - return new HookData().setId(hookData.id).setName(hookData.name).setDisplayName(hookData.displayName).setIsActive(hookData.isActive) - .setCreatedAt(hookData.createdAt).setUpdatedAt(hookData.updatedAt).setTemplateId(hookData.templateId) - .setTemplateName(hookData.templateName).setEvents(hookData.events).setConfig(hookData.config).setTemplates(templates) - .setGroupings(groupings); - } + private List groupings; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDeleteRequest.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDeleteRequest.java new file mode 100644 index 00000000000..06ffebd44f4 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDeleteRequest.java @@ -0,0 +1,38 @@ +/** + * 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.infrastructure.hooks.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HookDeleteRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long id; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDeleteResponse.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDeleteResponse.java new file mode 100644 index 00000000000..c8e033007e8 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDeleteResponse.java @@ -0,0 +1,38 @@ +/** + * 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.infrastructure.hooks.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HookDeleteResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Event.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDetailsData.java similarity index 78% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Event.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDetailsData.java index 7f754ef5236..72f14b81b7f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Event.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookDetailsData.java @@ -18,22 +18,25 @@ */ package org.apache.fineract.infrastructure.hooks.data; +import java.io.Serial; import java.io.Serializable; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +@Builder @Data @NoArgsConstructor +@AllArgsConstructor @Accessors(chain = true) -public final class Event implements Serializable { +public final class HookDetailsData implements Serializable { + @Serial private static final long serialVersionUID = 1L; - private String actionName; - private String entityName; - - public static Event instance(final String actionName, final String entityName) { - return new Event().setActionName(actionName).setEntityName(entityName); - } + private List templates; + private List groupings; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Entity.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookEntityData.java similarity index 86% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Entity.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookEntityData.java index de555551070..3ec63801e4a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Entity.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookEntityData.java @@ -18,18 +18,23 @@ */ package org.apache.fineract.infrastructure.hooks.data; +import java.io.Serial; import java.io.Serializable; import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -@SuppressWarnings("unused") +@Builder @Data @NoArgsConstructor +@AllArgsConstructor @Accessors(chain = true) -public class Entity implements Serializable { +public class HookEntityData implements Serializable { + @Serial private static final long serialVersionUID = 1L; private String name; diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookEventData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookEventData.java new file mode 100644 index 00000000000..a9aa140aade --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookEventData.java @@ -0,0 +1,45 @@ +/** + * 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.infrastructure.hooks.data; + +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.Accessors; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Accessors(chain = true) +public final class HookEventData implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private String actionName; + private String entityName; + + public static HookEventData instance(final String actionName, final String entityName) { + return new HookEventData().setActionName(actionName).setEntityName(entityName); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Field.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookFieldData.java similarity index 65% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Field.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookFieldData.java index 36ff8dc6027..a157428af9f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Field.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookFieldData.java @@ -18,17 +18,22 @@ */ package org.apache.fineract.infrastructure.hooks.data; +import java.io.Serial; import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -@SuppressWarnings("unused") +@Builder @Data @NoArgsConstructor +@AllArgsConstructor @Accessors(chain = true) -public final class Field implements Serializable { +public final class HookFieldData implements Serializable { + @Serial private static final long serialVersionUID = 1L; private String fieldName; @@ -37,11 +42,12 @@ public final class Field implements Serializable { private Boolean optional; private String placeholder; - public static Field fromConfig(final String fieldName, final String fieldValue) { - return new Field().setFieldName(fieldName).setFieldValue(fieldValue); + public static HookFieldData fromConfig(final String fieldName, final String fieldValue) { + return new HookFieldData().setFieldName(fieldName).setFieldValue(fieldValue); } - public static Field fromSchema(final String fieldType, final String fieldName, final Boolean optional, final String placeholder) { - return new Field().setFieldName(fieldName).setFieldType(fieldType).setOptional(optional).setPlaceholder(placeholder); + public static HookFieldData fromSchema(final String fieldType, final String fieldName, final Boolean optional, + final String placeholder) { + return new HookFieldData().setFieldName(fieldName).setFieldType(fieldType).setOptional(optional).setPlaceholder(placeholder); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Grouping.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookGroupingData.java similarity index 83% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Grouping.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookGroupingData.java index 5bbfbaf05dd..2712cf997c5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/Grouping.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookGroupingData.java @@ -18,20 +18,25 @@ */ package org.apache.fineract.infrastructure.hooks.data; +import java.io.Serial; import java.io.Serializable; import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -@SuppressWarnings("unused") +@Builder @Data @NoArgsConstructor +@AllArgsConstructor @Accessors(chain = true) -public class Grouping implements Serializable { +public class HookGroupingData implements Serializable { + @Serial private static final long serialVersionUID = 1L; private String name; - private List entities; + private List entities; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/data/SmsProviderData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookSmsProviderData.java similarity index 93% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/data/SmsProviderData.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookSmsProviderData.java index 21b31d28ba1..ac0ffe88ef2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/data/SmsProviderData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookSmsProviderData.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.infrastructure.hooks.processor.data; +package org.apache.fineract.infrastructure.hooks.data; import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.payloadURLName; import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.phoneNumberName; @@ -31,19 +31,18 @@ @Getter @Setter -public class SmsProviderData { +public class HookSmsProviderData { private String url; private String phoneNo; private String smsProvider; private String smsProviderAccountId; private String smsProviderToken; - private String tenantId; private String mifosToken; private String endpoint; - public SmsProviderData(final Set config) { + public HookSmsProviderData(final Set config) { for (final HookConfiguration conf : config) { final String fieldName = conf.getFieldName(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookTemplateData.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookTemplateData.java index 5589c24f9eb..694f3040a98 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookTemplateData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookTemplateData.java @@ -18,27 +18,32 @@ */ package org.apache.fineract.infrastructure.hooks.data; +import java.io.Serial; import java.io.Serializable; import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -@SuppressWarnings("unused") +@Builder @Data @NoArgsConstructor +@AllArgsConstructor @Accessors(chain = true) public final class HookTemplateData implements Serializable { + @Serial private static final long serialVersionUID = 1L; private Long id; private String name; // associations - private List schema; + private List schema; - public static HookTemplateData instance(final Long id, final String name, final List schema) { + public static HookTemplateData instance(final Long id, final String name, final List schema) { return new HookTemplateData().setId(id).setName(name).setSchema(schema); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookUpdateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookUpdateRequest.java new file mode 100644 index 00000000000..222b67f27cd --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookUpdateRequest.java @@ -0,0 +1,51 @@ +/** + * 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.infrastructure.hooks.data; + +import jakarta.validation.constraints.Size; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.FieldNameConstants; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@FieldNameConstants +public class HookUpdateRequest implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + // @NotNull(message = "{org.apache.fineract.infrastructure.hooks.id.not-null}") + private Long id; + @Size(max = 100, message = "{org.apache.fineract.infrastructure.hooks.name.size}") + private String name; + private Boolean isActive; + private String displayName; + private Long templateId; + private List events; + private Map config; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookUpdateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookUpdateResponse.java new file mode 100644 index 00000000000..a3ceae9343f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/HookUpdateResponse.java @@ -0,0 +1,40 @@ +/** + * 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.infrastructure.hooks.data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Map; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class HookUpdateResponse implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + private Long resourceId; + private Map changes; +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/Hook.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/Hook.java index 01015939a95..cdf2f0090e3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/Hook.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/Hook.java @@ -18,14 +18,6 @@ */ package org.apache.fineract.infrastructure.hooks.domain; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.configParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.displayNameParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.eventsParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.isActiveParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.templateIdParamName; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -35,18 +27,13 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; import java.util.Set; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.Accessors; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom; import org.apache.fineract.template.domain.Template; -import org.springframework.util.CollectionUtils; @Entity @Table(name = "m_hook") @@ -75,124 +62,4 @@ public final class Hook extends AbstractAuditableCustom { @ManyToOne(optional = true) @JoinColumn(name = "ugd_template_id", referencedColumnName = "id", nullable = true) private Template ugdTemplate; - - public static Hook fromJson(final JsonCommand command, final HookTemplate template, final Set config, - final Set events, final Template ugdTemplate) { - final String displayName = command.stringValueOfParameterNamed(displayNameParamName); - Boolean isActive = command.booleanObjectValueOfParameterNamed(isActiveParamName); - if (isActive == null) { - isActive = false; - } - return new Hook(template, displayName, isActive, config, events, ugdTemplate); - } - - private Hook(final HookTemplate template, final String displayName, final Boolean isActive, final Set config, - final Set events, final Template ugdTemplate) { - - this.template = template; - - if (StringUtils.isNotBlank(displayName)) { - this.name = displayName.trim(); - } else { - this.name = template.getName(); - } - this.isActive = isActive; - if (!CollectionUtils.isEmpty(config)) { - this.config = associateConfigWithThisHook(config); - } - if (!CollectionUtils.isEmpty(events)) { - this.events = associateEventsWithThisHook(events); - } - - this.ugdTemplate = ugdTemplate; - } - - private Set associateConfigWithThisHook(final Set config) { - for (final HookConfiguration hookConfiguration : config) { - hookConfiguration.setHook(this); - } - return config; - } - - private Set associateEventsWithThisHook(final Set events) { - for (final HookResource hookResource : events) { - hookResource.setHook(this); - } - return events; - } - - public Long getUgdTemplateId() { - Long templateId = null; - if (this.ugdTemplate != null) { - templateId = this.ugdTemplate.getId(); - } - return templateId; - } - - public Map update(final JsonCommand command) { - - final Map actualChanges = new LinkedHashMap<>(5); - - if (command.isChangeInStringParameterNamed(displayNameParamName, this.name)) { - final String newValue = command.stringValueOfParameterNamed(displayNameParamName); - actualChanges.put(displayNameParamName, newValue); - this.name = newValue; - } - - if (command.isChangeInBooleanParameterNamed(isActiveParamName, this.isActive)) { - final Boolean newValue = command.booleanObjectValueOfParameterNamed(isActiveParamName); - actualChanges.put(isActiveParamName, newValue); - this.isActive = newValue; - } - - if (command.isChangeInLongParameterNamed(templateIdParamName, getUgdTemplateId())) { - final Long newValue = command.longValueOfParameterNamed(templateIdParamName); - actualChanges.put(templateIdParamName, newValue); - } - - // events - if (command.hasParameter(eventsParamName)) { - final JsonArray jsonArray = command.arrayOfParameterNamed(eventsParamName); - if (jsonArray != null) { - actualChanges.put(eventsParamName, jsonArray); - } - } - - // config - if (command.hasParameter(configParamName)) { - final JsonElement element = command.parsedJson().getAsJsonObject().get(configParamName); - if (element != null) { - actualChanges.put(configParamName, element); - } - } - - return actualChanges; - } - - public boolean updateEvents(final Set newHookEvents) { - if (newHookEvents == null) { - return false; - } - - if (this.events == null) { - this.events = new HashSet<>(); - } - this.events.clear(); - this.events.addAll(associateEventsWithThisHook(newHookEvents)); - return true; - } - - public boolean updateConfig(final Set newHookConfig) { - if (newHookConfig == null) { - return false; - } - - if (this.config == null) { - this.config = new HashSet<>(); - } - this.config.clear(); - this.config.addAll(associateConfigWithThisHook(newHookConfig)); - return true; - } - } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/EventResultSetExtractor.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookEventResultSetExtractor.java similarity index 77% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/EventResultSetExtractor.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookEventResultSetExtractor.java index c91acfc2618..e3fa67237b8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/data/EventResultSetExtractor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookEventResultSetExtractor.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.fineract.infrastructure.hooks.data; +package org.apache.fineract.infrastructure.hooks.domain; import java.sql.ResultSet; import java.sql.SQLException; @@ -26,14 +26,17 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.fineract.infrastructure.hooks.data.HookEntityData; +import org.apache.fineract.infrastructure.hooks.data.HookGroupingData; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.ResultSetExtractor; -public class EventResultSetExtractor implements ResultSetExtractor> { +@Deprecated(forRemoval = true) +public class HookEventResultSetExtractor implements ResultSetExtractor> { @Override - public List extractData(final ResultSet rs) throws SQLException, DataAccessException { - final List groupings = new ArrayList<>(); + public List extractData(final ResultSet rs) throws SQLException, DataAccessException { + final List groupings = new ArrayList<>(); final Map>> groupToEntityMapping = new HashMap<>(); Map> entityToActionMapping = new HashMap<>(); @@ -63,11 +66,11 @@ public List extractData(final ResultSet rs) throws SQLException, DataA } for (final Map.Entry>> groupingEntry : groupToEntityMapping.entrySet()) { - final List entities = new ArrayList<>(); - final Grouping group = new Grouping(); + final List entities = new ArrayList<>(); + final HookGroupingData group = new HookGroupingData(); group.setName(groupingEntry.getKey()); for (final Map.Entry> entityEntry : groupingEntry.getValue().entrySet()) { - final Entity entity = new Entity(); + final HookEntityData entity = new HookEntityData(); entity.setName(entityEntry.getKey()); final List actions = new ArrayList<>(entityEntry.getValue()); Collections.sort(actions); @@ -75,12 +78,12 @@ public List extractData(final ResultSet rs) throws SQLException, DataA entities.add(entity); } - entities.sort(Comparator.comparing(Entity::getName)); + entities.sort(Comparator.comparing(HookEntityData::getName)); group.setEntities(entities); groupings.add(group); } - groupings.sort(Comparator.comparing(Grouping::getName)); + groupings.sort(Comparator.comparing(HookGroupingData::getName)); return groupings; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookResource.java index c9074112f1b..38542a6f450 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookResource.java @@ -46,8 +46,4 @@ public class HookResource extends AbstractPersistableCustom { @Column(name = "action_name", nullable = false, length = 45) private String actionName; - - public static HookResource createNewWithoutHook(final String entityName, final String actionName) { - return new HookResource().setEntityName(entityName).setActionName(actionName); - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/Schema.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookSchema.java similarity index 96% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/Schema.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookSchema.java index c2c3ee98f65..829716800d7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/Schema.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookSchema.java @@ -35,7 +35,7 @@ @Setter @NoArgsConstructor @Accessors(chain = true) -public class Schema extends AbstractPersistableCustom { +public class HookSchema extends AbstractPersistableCustom { @ManyToOne(optional = false) @JoinColumn(name = "hook_template_id", referencedColumnName = "id", nullable = false) diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookTemplate.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookTemplate.java index ced92767943..34111560be2 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookTemplate.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/domain/HookTemplate.java @@ -18,8 +18,6 @@ */ package org.apache.fineract.infrastructure.hooks.domain; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.nameParamName; - import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -32,8 +30,6 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.experimental.Accessors; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.infrastructure.core.api.JsonCommand; import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; @Entity @@ -48,19 +44,5 @@ public final class HookTemplate extends AbstractPersistableCustom { private String name; @OneToMany(cascade = CascadeType.ALL, mappedBy = "template", orphanRemoval = true, fetch = FetchType.EAGER) - private Set fields = new HashSet<>(); - - private HookTemplate(final String name) { - - if (StringUtils.isNotBlank(name)) { - this.name = name.trim(); - } else { - this.name = null; - } - } - - public static HookTemplate fromJson(final JsonCommand command) { - final String name = command.stringValueOfParameterNamed(nameParamName); - return new HookTemplate(name); - } + private Set fields = new HashSet<>(); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/UpdateHookCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookCreateCommandHandler.java similarity index 56% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/UpdateHookCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookCreateCommandHandler.java index 652c82c78be..e30aef98ed6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/UpdateHookCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookCreateCommandHandler.java @@ -18,25 +18,33 @@ */ package org.apache.fineract.infrastructure.hooks.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -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 lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.infrastructure.hooks.data.HookCreateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookCreateResponse; import org.apache.fineract.infrastructure.hooks.service.HookWritePlatformService; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "HOOK", action = "UPDATE") +@Slf4j +@Component @RequiredArgsConstructor -public class UpdateHookCommandHandler implements NewCommandSourceHandler { +public class HookCreateCommandHandler implements CommandHandler { private final HookWritePlatformService writePlatformService; + @Retry(name = "commandHookCreate", fallbackMethod = "fallback") + @Override @Transactional + public HookCreateResponse handle(Command command) { + return this.writePlatformService.createHook(command.getPayload()); + } + @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.writePlatformService.updateHook(command.entityId(), command); + public HookCreateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/CreateHookCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookDeleteCommandHandler.java similarity index 57% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/CreateHookCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookDeleteCommandHandler.java index 79613ce6b68..13fa20cc42b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/CreateHookCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookDeleteCommandHandler.java @@ -18,26 +18,33 @@ */ package org.apache.fineract.infrastructure.hooks.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -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 lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteRequest; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteResponse; import org.apache.fineract.infrastructure.hooks.service.HookWritePlatformService; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "HOOK", action = "CREATE") +@Slf4j +@Component @RequiredArgsConstructor -public class CreateHookCommandHandler implements NewCommandSourceHandler { +public class HookDeleteCommandHandler implements CommandHandler { private final HookWritePlatformService writePlatformService; - @Transactional + @Retry(name = "commandHookDelete", fallbackMethod = "fallback") @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.writePlatformService.createHook(command); + @Transactional + public HookDeleteResponse handle(Command command) { + return writePlatformService.deleteHook(command.getPayload()); } + @Override + public HookDeleteResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/DeleteHookCommandHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookUpdateCommandHandler.java similarity index 56% rename from fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/DeleteHookCommandHandler.java rename to fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookUpdateCommandHandler.java index c0768e5f800..79426de1e30 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/DeleteHookCommandHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/handler/HookUpdateCommandHandler.java @@ -18,25 +18,33 @@ */ package org.apache.fineract.infrastructure.hooks.handler; +import io.github.resilience4j.retry.annotation.Retry; import lombok.RequiredArgsConstructor; -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 lombok.extern.slf4j.Slf4j; +import org.apache.fineract.command.core.Command; +import org.apache.fineract.command.core.CommandHandler; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateResponse; import org.apache.fineract.infrastructure.hooks.service.HookWritePlatformService; -import org.springframework.stereotype.Service; +import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Service -@CommandType(entity = "HOOK", action = "DELETE") +@Slf4j +@Component @RequiredArgsConstructor -public class DeleteHookCommandHandler implements NewCommandSourceHandler { +public class HookUpdateCommandHandler implements CommandHandler { private final HookWritePlatformService writePlatformService; + @Retry(name = "commandHookUpdate", fallbackMethod = "fallback") + @Override @Transactional + public HookUpdateResponse handle(Command command) { + return writePlatformService.updateHook(command.getPayload()); + } + @Override - public CommandProcessingResult processCommand(final JsonCommand command) { - return this.writePlatformService.deleteHook(command.entityId()); + public HookUpdateResponse fallback(Command command, Throwable t) { + return CommandHandler.super.fallback(command, t); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/mapper/HookEventMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/mapper/HookEventMapper.java new file mode 100644 index 00000000000..e7121d5936c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/mapper/HookEventMapper.java @@ -0,0 +1,37 @@ +/** + * 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.infrastructure.hooks.mapper; + +import java.util.List; +import java.util.Set; +import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig; +import org.apache.fineract.infrastructure.hooks.data.HookEventData; +import org.apache.fineract.infrastructure.hooks.domain.HookResource; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapstructMapperConfig.class) +public interface HookEventMapper { + + @Mapping(ignore = true, target = "id") + @Mapping(ignore = true, target = "hook") + HookResource map(HookEventData source); + + Set map(List source); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/mapper/HookFieldMapper.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/mapper/HookFieldMapper.java new file mode 100644 index 00000000000..d209362472b --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/mapper/HookFieldMapper.java @@ -0,0 +1,37 @@ +/** + * 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.infrastructure.hooks.mapper; + +import java.util.List; +import java.util.Set; +import org.apache.fineract.infrastructure.core.config.MapstructMapperConfig; +import org.apache.fineract.infrastructure.hooks.data.HookFieldData; +import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +@Mapper(config = MapstructMapperConfig.class) +public interface HookFieldMapper { + + @Mapping(ignore = true, target = "id") + @Mapping(ignore = true, target = "hook") + HookConfiguration map(HookFieldData source); + + Set map(List source); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java index 36ccaa2ff36..16df82ad2a5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/TwilioHookProcessor.java @@ -31,10 +31,10 @@ import java.util.Map; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.domain.FineractContext; +import org.apache.fineract.infrastructure.hooks.data.HookSmsProviderData; import org.apache.fineract.infrastructure.hooks.domain.Hook; import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration; import org.apache.fineract.infrastructure.hooks.domain.HookConfigurationRepository; -import org.apache.fineract.infrastructure.hooks.processor.data.SmsProviderData; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.template.service.TemplateMergeService; @@ -54,13 +54,13 @@ public class TwilioHookProcessor implements HookProcessor { public void process(final Hook hook, final String payload, final String entityName, final String actionName, final FineractContext context) throws IOException { - final SmsProviderData smsProviderData = new SmsProviderData(hook.getConfig()); + final HookSmsProviderData smsProviderData = new HookSmsProviderData(hook.getConfig()); sendRequest(smsProviderData, payload, entityName, actionName, hook, context); } @SuppressWarnings("unchecked") - private void sendRequest(final SmsProviderData smsProviderData, final String payload, String entityName, String actionName, + private void sendRequest(final HookSmsProviderData smsProviderData, final String payload, String entityName, String actionName, final Hook hook, final FineractContext context) throws IOException { final WebHookService service = processorHelper.createWebHookService(smsProviderData.getUrl()); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java index 9419a476591..40938c6d8f8 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/processor/WebHookService.java @@ -20,7 +20,7 @@ import com.google.gson.JsonObject; import java.util.Map; -import org.apache.fineract.infrastructure.hooks.processor.data.SmsProviderData; +import org.apache.fineract.infrastructure.hooks.data.HookSmsProviderData; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.FieldMap; @@ -58,6 +58,6 @@ Call sendSmsBridgeRequest(@Header(ENTITY_HEADER) String entityHeader, @Hea @Header(TENANT_HEADER) String tenantHeader, @Header(API_KEY_HEADER) String apiKeyHeader, @Body JsonObject result); @POST("/configuration") - Call sendSmsBridgeConfigRequest(@Body SmsProviderData config); + Call sendSmsBridgeConfigRequest(@Body HookSmsProviderData config); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/serialization/HookCommandFromApiJsonDeserializer.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/serialization/HookCommandFromApiJsonDeserializer.java deleted file mode 100644 index 758a242cad3..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/serialization/HookCommandFromApiJsonDeserializer.java +++ /dev/null @@ -1,107 +0,0 @@ -/** - * 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.infrastructure.hooks.serialization; - -import com.google.gson.JsonElement; -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; -import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; -import org.apache.fineract.infrastructure.core.exception.InvalidJsonException; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.infrastructure.hooks.api.HookApiConstants; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class HookCommandFromApiJsonDeserializer { - - /** - * The parameters supported for this command. - */ - private final Set supportedParameters = new HashSet<>( - Arrays.asList("name", "displayName", "isActive", "events", "config", "templateId")); - private final FromJsonHelper fromApiJsonHelper; - - public void validateForCreate(final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("hook"); - - final JsonElement element = this.fromApiJsonHelper.parse(json); - - final String name = this.fromApiJsonHelper.extractStringNamed("name", element); - baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(100); - - if (this.fromApiJsonHelper.parameterExists(HookApiConstants.templateIdParamName, element)) { - final Long templateId = this.fromApiJsonHelper.extractLongNamed(HookApiConstants.templateIdParamName, element); - baseDataValidator.reset().parameter(HookApiConstants.templateIdParamName).value(templateId).notNull().integerGreaterThanZero(); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - public void validateForUpdate(final String json) { - if (StringUtils.isBlank(json)) { - throw new InvalidJsonException(); - } - - final Type typeOfMap = new TypeToken>() {}.getType(); - this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, this.supportedParameters); - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("hook"); - - final JsonElement element = this.fromApiJsonHelper.parse(json); - if (this.fromApiJsonHelper.parameterExists("name", element)) { - final String name = this.fromApiJsonHelper.extractStringNamed("name", element); - baseDataValidator.reset().parameter("name").value(name).notBlank().notExceedingLengthOf(100); - } - - if (this.fromApiJsonHelper.parameterExists(HookApiConstants.templateIdParamName, element)) { - final Long templateId = this.fromApiJsonHelper.extractLongNamed(HookApiConstants.templateIdParamName, element); - baseDataValidator.reset().parameter(HookApiConstants.templateIdParamName).value(templateId).notNull().integerGreaterThanZero(); - } - - throwExceptionIfValidationWarningsExist(dataValidationErrors); - } - - private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", - dataValidationErrors); - } - } - -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformService.java index 33c80dbef41..fd3054af15d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformService.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.List; import org.apache.fineract.infrastructure.hooks.data.HookData; +import org.apache.fineract.infrastructure.hooks.data.HookDetailsData; import org.apache.fineract.infrastructure.hooks.domain.Hook; public interface HookReadPlatformService { @@ -29,7 +30,8 @@ public interface HookReadPlatformService { HookData retrieveHook(Long hookId); + // TODO: don't leak database domain to the outside world!!! List retrieveHooksByEvent(String entityName, String actionName); - HookData retrieveNewHookDetails(String templateName); + HookDetailsData retrieveNewHookDetails(String templateName); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformServiceImpl.java index 43b44babe7f..a2279e1d4da 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookReadPlatformServiceImpl.java @@ -25,16 +25,16 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.domain.JdbcSupport; -import org.apache.fineract.infrastructure.hooks.data.Event; -import org.apache.fineract.infrastructure.hooks.data.EventResultSetExtractor; -import org.apache.fineract.infrastructure.hooks.data.Field; -import org.apache.fineract.infrastructure.hooks.data.Grouping; import org.apache.fineract.infrastructure.hooks.data.HookData; +import org.apache.fineract.infrastructure.hooks.data.HookDetailsData; +import org.apache.fineract.infrastructure.hooks.data.HookEventData; +import org.apache.fineract.infrastructure.hooks.data.HookFieldData; +import org.apache.fineract.infrastructure.hooks.data.HookGroupingData; import org.apache.fineract.infrastructure.hooks.data.HookTemplateData; import org.apache.fineract.infrastructure.hooks.domain.Hook; +import org.apache.fineract.infrastructure.hooks.domain.HookEventResultSetExtractor; import org.apache.fineract.infrastructure.hooks.domain.HookRepository; import org.apache.fineract.infrastructure.hooks.exception.HookNotFoundException; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.springframework.cache.annotation.Cacheable; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -47,11 +47,9 @@ public class HookReadPlatformServiceImpl implements HookReadPlatformService { private final JdbcTemplate jdbcTemplate; private final HookRepository hookRepository; - private final PlatformSecurityContext context; @Override public Collection retrieveAllHooks() { - context.authenticatedUser(); final HookMapper rm = new HookMapper(jdbcTemplate); final String sql = "select " + rm.schema() + " order by h.name"; @@ -61,7 +59,6 @@ public Collection retrieveAllHooks() { @Override public HookData retrieveHook(final Long hookId) { try { - context.authenticatedUser(); final HookMapper rm = new HookMapper(jdbcTemplate); final String sql = "select " + rm.schema() + " where h.id = ?"; @@ -79,9 +76,7 @@ public List retrieveHooksByEvent(final String entityName, final String act } @Override - public HookData retrieveNewHookDetails(final String templateName) { - - context.authenticatedUser(); + public HookDetailsData retrieveNewHookDetails(final String templateName) { final TemplateMapper rm = new TemplateMapper(jdbcTemplate); final String sql; List templateData; @@ -94,15 +89,15 @@ public HookData retrieveNewHookDetails(final String templateName) { templateData = jdbcTemplate.query(sql, rm, templateName); // NOSONAR } - final List events = getTemplateForEvents(); + final List events = getTemplateForEvents(); - return HookData.template(templateData, events); + return HookDetailsData.builder().templates(templateData).groupings(events).build(); } - private List getTemplateForEvents() { + private List getTemplateForEvents() { final String sql = "select p.grouping, p.entity_name, p.action_name from m_permission p " + " where p.action_name NOT LIKE '%CHECKER%' AND p.action_name NOT LIKE '%READ%' " + " order by p.grouping, p.entity_name "; - final EventResultSetExtractor extractor = new EventResultSetExtractor(); + final HookEventResultSetExtractor extractor = new HookEventResultSetExtractor(); return jdbcTemplate.query(sql, extractor); } @@ -129,14 +124,14 @@ public HookData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int final LocalDate updatedAt = JdbcSupport.getLocalDate(rs, "lastmodified_date"); final Long templateId = rs.getLong("ugd_template_id"); final String templateName = rs.getString("ugd_template_name"); - final List registeredEvents = retrieveEvents(id); - final List config = retrieveConfig(id); + final List registeredEvents = retrieveEvents(id); + final List config = retrieveConfig(id); - return HookData.instance(id, name, displayname, isActive, createdAt, updatedAt, templateId, registeredEvents, config, - templateName); + return HookData.builder().id(id).name(name).displayName(displayname).isActive(isActive).createdAt(createdAt) + .updatedAt(updatedAt).templateId(templateId).events(registeredEvents).config(config).templateName(templateName).build(); } - private List retrieveEvents(final Long hookId) { + private List retrieveEvents(final Long hookId) { final HookEventMapper rm = new HookEventMapper(); final String sql = "select " + rm.schema() + " where h.id= ?"; @@ -144,7 +139,7 @@ private List retrieveEvents(final Long hookId) { return jdbcTemplate.query(sql, rm, hookId); // NOSONAR } - private List retrieveConfig(final Long hookId) { + private List retrieveConfig(final Long hookId) { final HookConfigMapper rm = new HookConfigMapper(); final String sql = "select " + rm.schema() + " where h.id= ? order by hc.field_name"; @@ -153,31 +148,31 @@ private List retrieveConfig(final Long hookId) { } } - private static final class HookEventMapper implements RowMapper { + private static final class HookEventMapper implements RowMapper { public String schema() { return " re.action_name, re.entity_name from m_hook h inner join m_hook_registered_events re on h.id = re.hook_id "; } @Override - public Event mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + public HookEventData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { final String actionName = rs.getString("action_name"); final String entityName = rs.getString("entity_name"); - return Event.instance(actionName, entityName); + return HookEventData.instance(actionName, entityName); } } - private static final class HookConfigMapper implements RowMapper { + private static final class HookConfigMapper implements RowMapper { public String schema() { return " hc.field_name, hc.field_value from m_hook h inner join m_hook_configuration hc on h.id = hc.hook_id "; } @Override - public Field mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + public HookFieldData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { final String fieldName = rs.getString("field_name"); final String fieldValue = rs.getString("field_value"); - return Field.fromConfig(fieldName, fieldValue); + return HookFieldData.fromConfig(fieldName, fieldValue); } } @@ -195,12 +190,12 @@ public HookTemplateData mapRow(final ResultSet rs, @SuppressWarnings("unused") f final Long id = rs.getLong("id"); final String name = rs.getString("name"); - final List schema = retrieveSchema(id); + final List schema = retrieveSchema(id); return HookTemplateData.instance(id, name, schema); } - private List retrieveSchema(final Long templateId) { + private List retrieveSchema(final Long templateId) { final TemplateSchemaMapper rm = new TemplateSchemaMapper(); final String sql = "select " + rm.schema() + " where s.id= ? order by hs.field_name "; @@ -209,7 +204,7 @@ private List retrieveSchema(final Long templateId) { } } - private static final class TemplateSchemaMapper implements RowMapper { + private static final class TemplateSchemaMapper implements RowMapper { public String schema() { return " hs.field_type, hs.field_name, hs.placeholder, hs.optional from m_hook_templates s " @@ -217,12 +212,12 @@ public String schema() { } @Override - public Field mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + public HookFieldData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { final String fieldName = rs.getString("field_name"); final String fieldType = rs.getString("field_type"); final Boolean optional = rs.getBoolean("optional"); final String placeholder = rs.getString("placeholder"); - return Field.fromSchema(fieldType, fieldName, optional, placeholder); + return HookFieldData.fromSchema(fieldType, fieldName, optional, placeholder); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformService.java index 56d8f409641..b4fdc80eda4 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformService.java @@ -18,15 +18,18 @@ */ package org.apache.fineract.infrastructure.hooks.service; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.hooks.data.HookCreateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookCreateResponse; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteRequest; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteResponse; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateResponse; public interface HookWritePlatformService { - CommandProcessingResult createHook(JsonCommand command); + HookCreateResponse createHook(HookCreateRequest request); - CommandProcessingResult updateHook(Long hookId, JsonCommand command); - - CommandProcessingResult deleteHook(Long hookId); + HookUpdateResponse updateHook(HookUpdateRequest request); + HookDeleteResponse deleteHook(HookDeleteRequest request); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceImpl.java new file mode 100644 index 00000000000..d48c9718d64 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceImpl.java @@ -0,0 +1,283 @@ +/** + * 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.infrastructure.hooks.service; + +import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.contentTypeName; +import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.payloadURLName; +import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.webTemplateName; + +import jakarta.persistence.PersistenceException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.fineract.infrastructure.core.data.ApiParameterError; +import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; +import org.apache.fineract.infrastructure.core.exception.ErrorHandler; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; +import org.apache.fineract.infrastructure.hooks.data.HookCreateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookCreateResponse; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteRequest; +import org.apache.fineract.infrastructure.hooks.data.HookDeleteResponse; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateRequest; +import org.apache.fineract.infrastructure.hooks.data.HookUpdateResponse; +import org.apache.fineract.infrastructure.hooks.domain.Hook; +import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration; +import org.apache.fineract.infrastructure.hooks.domain.HookRepository; +import org.apache.fineract.infrastructure.hooks.domain.HookResource; +import org.apache.fineract.infrastructure.hooks.domain.HookSchema; +import org.apache.fineract.infrastructure.hooks.domain.HookTemplate; +import org.apache.fineract.infrastructure.hooks.domain.HookTemplateRepository; +import org.apache.fineract.infrastructure.hooks.exception.HookNotFoundException; +import org.apache.fineract.infrastructure.hooks.exception.HookTemplateNotFoundException; +import org.apache.fineract.infrastructure.hooks.mapper.HookEventMapper; +import org.apache.fineract.infrastructure.hooks.mapper.HookFieldMapper; +import org.apache.fineract.infrastructure.hooks.processor.ProcessorHelper; +import org.apache.fineract.template.domain.Template; +import org.apache.fineract.template.domain.TemplateRepository; +import org.apache.fineract.template.exception.TemplateNotFoundException; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.orm.jpa.JpaSystemException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class HookWritePlatformServiceImpl implements HookWritePlatformService { + + private final HookRepository hookRepository; + private final HookTemplateRepository hookTemplateRepository; + private final TemplateRepository ugdTemplateRepository; + private final ProcessorHelper processorHelper; + private final HookEventMapper hookEventMapper; + private final HookFieldMapper hookFieldMapper; + + @Transactional + @Override + @CacheEvict(value = "hooks", allEntries = true) + public HookCreateResponse createHook(HookCreateRequest request) { + + try { + var template = retrieveHookTemplateBy(request.getName()); + var resources = hookEventMapper.map(request.getEvents()); + var configurations = assembleConfig(request.getConfig(), template); + + Template ugdTemplate = null; + + if (request.getTemplateId() != null) { + ugdTemplate = ugdTemplateRepository.findById(request.getTemplateId()) + .orElseThrow(() -> new TemplateNotFoundException(request.getTemplateId())); + } + + var hook = new Hook().setIsActive(Boolean.TRUE.equals(request.getIsActive())).setTemplate(template).setUgdTemplate(ugdTemplate) + .setConfig(configurations).setEvents(resources) + .setName(StringUtils.isNotBlank(request.getDisplayName()) ? request.getDisplayName().trim() : template.getName()); + hook.getConfig().forEach(hookConfiguration -> hookConfiguration.setHook(hook)); + hook.getEvents().forEach(hookResource -> hookResource.setHook(hook)); + + validateHookRules(template, configurations, resources); + + this.hookRepository.saveAndFlush(hook); + + return HookCreateResponse.builder().resourceId(hook.getId()).build(); + } catch (final JpaSystemException | DataIntegrityViolationException dve) { + throw handleHookDataIntegrityIssues(request.getName(), dve.getMostSpecificCause(), dve); + } catch (final PersistenceException dve) { + Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); + throw handleHookDataIntegrityIssues(request.getName(), throwable, dve); + } + } + + @Transactional + @Override + @CacheEvict(value = "hooks", allEntries = true) + public HookUpdateResponse updateHook(HookUpdateRequest request) { + + try { + var hook = hookRepository.findById(request.getId()).orElseThrow(() -> new HookNotFoundException(request.getId())); + var changes = new HashMap(); + + if (!Objects.equals(request.getDisplayName(), hook.getName())) { + changes.put(HookUpdateRequest.Fields.displayName, request.getDisplayName()); + } + if (!Objects.equals(request.getIsActive(), hook.getIsActive())) { + changes.put(HookUpdateRequest.Fields.isActive, request.getIsActive()); + } + var optionalTemplateId = Optional.ofNullable(request.getTemplateId()); + + if (optionalTemplateId.isPresent() && !Objects.equals(request.getTemplateId(), + Optional.ofNullable(hook.getTemplate()).map(AbstractPersistableCustom::getId).orElse(null))) { + changes.put(HookUpdateRequest.Fields.templateId, request.getTemplateId()); + + var ugdTemplate = ugdTemplateRepository.findById(request.getTemplateId()).orElse(null); + + if (ugdTemplate == null) { + changes.remove(HookUpdateRequest.Fields.templateId); + throw new TemplateNotFoundException(request.getTemplateId()); + } + + hook.setUgdTemplate(ugdTemplate); + } + if (Objects.nonNull(request.getEvents()) && !request.getEvents().isEmpty()) { + changes.put(HookUpdateRequest.Fields.events, request.getEvents()); + + hook.setEvents(hookEventMapper.map(request.getEvents())); + hook.getEvents().forEach(hookResource -> hookResource.setHook(hook)); + } + if (Objects.nonNull(request.getConfig()) && !request.getConfig().isEmpty()) { + changes.put(HookUpdateRequest.Fields.config, request.getConfig()); + + hook.setConfig(assembleConfig(request.getConfig(), hook.getTemplate())); + hook.getConfig().forEach(hookConfiguration -> hookConfiguration.setHook(hook)); + } + + if (!changes.isEmpty()) { + hookRepository.saveAndFlush(hook); + } + + return HookUpdateResponse.builder().resourceId(hook.getId()).changes(changes).build(); + } catch (final JpaSystemException | DataIntegrityViolationException dve) { + throw handleHookDataIntegrityIssues(request.getName(), dve.getMostSpecificCause(), dve); + } catch (final PersistenceException dve) { + Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); + throw handleHookDataIntegrityIssues(request.getName(), throwable, dve); + } + } + + @Transactional + @Override + @CacheEvict(value = "hooks", allEntries = true) + public HookDeleteResponse deleteHook(HookDeleteRequest request) { + var hook = hookRepository.findById(request.getId()).orElseThrow(() -> new HookNotFoundException(request.getId())); + + try { + this.hookRepository.delete(hook); + } catch (final JpaSystemException | DataIntegrityViolationException e) { + throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", + "Unknown data integrity issue with resource: " + e.getMostSpecificCause(), e); + } + return HookDeleteResponse.builder().resourceId(request.getId()).build(); + } + + private HookTemplate retrieveHookTemplateBy(final String templateName) { + var template = this.hookTemplateRepository.findOne(templateName); + + if (template == null) { + throw new HookTemplateNotFoundException(templateName); + } + + return template; + } + + private Set assembleConfig(final Map hookConfig, final HookTemplate template) { + + final Set configuration = new HashSet<>(); + final Set fields = template.getFields(); + + for (final Map.Entry configEntry : hookConfig.entrySet()) { + for (final HookSchema field : fields) { + final String fieldName = field.getFieldName(); + if (fieldName.equalsIgnoreCase(configEntry.getKey())) { + + final HookConfiguration config = HookConfiguration.createNewWithoutHook(field.getFieldType(), configEntry.getKey(), + configEntry.getValue()); + configuration.add(config); + break; + } + } + + } + + return configuration; + } + + private void validateHookRules(final HookTemplate template, final Set config, Set events) { + + final List dataValidationErrors = new ArrayList<>(); + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("hook"); + + if (!template.getName().equalsIgnoreCase(webTemplateName) && hookRepository.findOneByTemplateId(template.getId()) != null) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("multiple.non.web.template.hooks.not.supported"); + } + + for (final HookConfiguration conf : config) { + final String fieldValue = conf.getFieldValue(); + if (conf.getFieldName().equals(contentTypeName)) { + if ((!fieldValue.equalsIgnoreCase("json") && !fieldValue.equalsIgnoreCase("form"))) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("content.type.must.be.json.or.form"); + } + } + + if (conf.getFieldName().equals(payloadURLName)) { + try { + var service = processorHelper.createWebHookService(fieldValue); + service.sendEmptyRequest().execute(); + } catch (IOException re) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("url.invalid"); + } + } + } + + if (events == null || events.isEmpty()) { + baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("registered.events.cannot.be.empty"); + } + + for (final HookSchema field : template.getFields()) { + if (!field.isOptional()) { + boolean found = false; + + for (final HookConfiguration conf : config) { + if (field.getFieldName().equals(conf.getFieldName())) { + found = true; + break; + } + } + + if (!found) { + baseDataValidator.reset().value(field.getFieldName()) + .failWithCodeNoParameterAddedToErrorCode("required.config.field.not.provided"); + } + } + } + + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } + + private RuntimeException handleHookDataIntegrityIssues(final String name, final Throwable realCause, final Exception dve) { + if (realCause.getMessage().contains("hook_name")) { + return new PlatformDataIntegrityException("error.msg.hook.duplicate.name", "A hook with name '" + name + "' already exists", + "name", name); + } + return ErrorHandler.getMappable(dve, "error.msg.unknown.data.integrity.issue", + "Unknown data integrity issue with resource: " + realCause.getMessage()); + } +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java deleted file mode 100644 index fa28a0f6693..00000000000 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/hooks/service/HookWritePlatformServiceJpaRepositoryImpl.java +++ /dev/null @@ -1,321 +0,0 @@ -/** - * 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.infrastructure.hooks.service; - -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.actionNameParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.configParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.contentTypeName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.entityNameParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.eventsParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.nameParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.payloadURLName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.templateIdParamName; -import static org.apache.fineract.infrastructure.hooks.api.HookApiConstants.webTemplateName; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import jakarta.persistence.PersistenceException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.fineract.infrastructure.core.api.JsonCommand; -import org.apache.fineract.infrastructure.core.data.ApiParameterError; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; -import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder; -import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; -import org.apache.fineract.infrastructure.core.exception.ErrorHandler; -import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; -import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; -import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper; -import org.apache.fineract.infrastructure.hooks.domain.Hook; -import org.apache.fineract.infrastructure.hooks.domain.HookConfiguration; -import org.apache.fineract.infrastructure.hooks.domain.HookRepository; -import org.apache.fineract.infrastructure.hooks.domain.HookResource; -import org.apache.fineract.infrastructure.hooks.domain.HookTemplate; -import org.apache.fineract.infrastructure.hooks.domain.HookTemplateRepository; -import org.apache.fineract.infrastructure.hooks.domain.Schema; -import org.apache.fineract.infrastructure.hooks.exception.HookNotFoundException; -import org.apache.fineract.infrastructure.hooks.exception.HookTemplateNotFoundException; -import org.apache.fineract.infrastructure.hooks.processor.ProcessorHelper; -import org.apache.fineract.infrastructure.hooks.processor.WebHookService; -import org.apache.fineract.infrastructure.hooks.serialization.HookCommandFromApiJsonDeserializer; -import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.apache.fineract.template.domain.Template; -import org.apache.fineract.template.domain.TemplateRepository; -import org.apache.fineract.template.exception.TemplateNotFoundException; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.orm.jpa.JpaSystemException; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@RequiredArgsConstructor -public class HookWritePlatformServiceJpaRepositoryImpl implements HookWritePlatformService { - - private final PlatformSecurityContext context; - private final HookRepository hookRepository; - private final HookTemplateRepository hookTemplateRepository; - private final TemplateRepository ugdTemplateRepository; - private final HookCommandFromApiJsonDeserializer fromApiJsonDeserializer; - private final FromJsonHelper fromApiJsonHelper; - private final ProcessorHelper processorHelper; - - @Transactional - @Override - @CacheEvict(value = "hooks", allEntries = true) - public CommandProcessingResult createHook(final JsonCommand command) { - - try { - this.context.authenticatedUser(); - - this.fromApiJsonDeserializer.validateForCreate(command.json()); - - final HookTemplate template = retrieveHookTemplateBy(command.stringValueOfParameterNamed(nameParamName)); - final String configJson = command.jsonFragment(configParamName); - final Set config = assembleConfig(command.mapValueOfParameterNamed(configJson), template); - final JsonArray events = command.arrayOfParameterNamed(eventsParamName); - final Set allEvents = assembleSetOfEvents(events); - Template ugdTemplate = null; - if (command.hasParameter(templateIdParamName)) { - final Long ugdTemplateId = command.longValueOfParameterNamed(templateIdParamName); - ugdTemplate = this.ugdTemplateRepository.findById(ugdTemplateId) - .orElseThrow(() -> new TemplateNotFoundException(ugdTemplateId)); - } - final Hook hook = Hook.fromJson(command, template, config, allEvents, ugdTemplate); - - validateHookRules(template, config, allEvents); - - this.hookRepository.saveAndFlush(hook); - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withEntityId(hook.getId()) // - .build(); - } catch (final JpaSystemException | DataIntegrityViolationException dve) { - handleHookDataIntegrityIssues(command, dve.getMostSpecificCause(), dve); - return CommandProcessingResult.empty(); - } catch (final PersistenceException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - handleHookDataIntegrityIssues(command, throwable, dve); - return CommandProcessingResult.empty(); - } - } - - @Transactional - @Override - @CacheEvict(value = "hooks", allEntries = true) - public CommandProcessingResult updateHook(final Long hookId, final JsonCommand command) { - - try { - this.context.authenticatedUser(); - - this.fromApiJsonDeserializer.validateForUpdate(command.json()); - - final Hook hook = retrieveHookBy(hookId); - final HookTemplate template = hook.getTemplate(); - final Map changes = hook.update(command); - - if (!changes.isEmpty()) { - - if (changes.containsKey(templateIdParamName)) { - final Long ugdTemplateId = command.longValueOfParameterNamed(templateIdParamName); - final Template ugdTemplate = this.ugdTemplateRepository.findById(ugdTemplateId).orElse(null); - if (ugdTemplate == null) { - changes.remove(templateIdParamName); - throw new TemplateNotFoundException(ugdTemplateId); - } - hook.setUgdTemplate(ugdTemplate); - } - - if (changes.containsKey(eventsParamName)) { - final Set events = assembleSetOfEvents(command.arrayOfParameterNamed(eventsParamName)); - final boolean updated = hook.updateEvents(events); - if (!updated) { - changes.remove(eventsParamName); - } - } - - if (changes.containsKey(configParamName)) { - final String configJson = command.jsonFragment(configParamName); - final Set config = assembleConfig(command.mapValueOfParameterNamed(configJson), template); - final boolean updated = hook.updateConfig(config); - if (!updated) { - changes.remove(configParamName); - } - } - - this.hookRepository.saveAndFlush(hook); - } - - return new CommandProcessingResultBuilder() // - .withCommandId(command.commandId()) // - .withEntityId(hookId) // - .with(changes) // - .build(); - } catch (final JpaSystemException | DataIntegrityViolationException dve) { - handleHookDataIntegrityIssues(command, dve.getMostSpecificCause(), dve); - return CommandProcessingResult.empty(); - } catch (final PersistenceException dve) { - Throwable throwable = ExceptionUtils.getRootCause(dve.getCause()); - handleHookDataIntegrityIssues(command, throwable, dve); - return CommandProcessingResult.empty(); - } - } - - @Transactional - @Override - @CacheEvict(value = "hooks", allEntries = true) - public CommandProcessingResult deleteHook(final Long hookId) { - - this.context.authenticatedUser(); - final Hook hook = retrieveHookBy(hookId); - try { - this.hookRepository.delete(hook); - } catch (final JpaSystemException | DataIntegrityViolationException e) { - throw new PlatformDataIntegrityException("error.msg.unknown.data.integrity.issue", - "Unknown data integrity issue with resource: " + e.getMostSpecificCause(), e); - } - return new CommandProcessingResultBuilder() // - .withEntityId(hookId) // - .build(); - } - - private Hook retrieveHookBy(final Long hookId) { - return this.hookRepository.findById(hookId).orElseThrow(() -> new HookNotFoundException(hookId)); - } - - private HookTemplate retrieveHookTemplateBy(final String templateName) { - final HookTemplate template = this.hookTemplateRepository.findOne(templateName); - if (template == null) { - throw new HookTemplateNotFoundException(templateName); - } - return template; - } - - private Set assembleConfig(final Map hookConfig, final HookTemplate template) { - - final Set configuration = new HashSet<>(); - final Set fields = template.getFields(); - - for (final Map.Entry configEntry : hookConfig.entrySet()) { - for (final Schema field : fields) { - final String fieldName = field.getFieldName(); - if (fieldName.equalsIgnoreCase(configEntry.getKey())) { - - final HookConfiguration config = HookConfiguration.createNewWithoutHook(field.getFieldType(), configEntry.getKey(), - configEntry.getValue()); - configuration.add(config); - break; - } - } - - } - - return configuration; - } - - private Set assembleSetOfEvents(final JsonArray eventsArray) { - - final Set allEvents = new HashSet<>(); - - for (int i = 0; i < eventsArray.size(); i++) { - - final JsonObject eventElement = eventsArray.get(i).getAsJsonObject(); - - final String entityName = this.fromApiJsonHelper.extractStringNamed(entityNameParamName, eventElement); - final String actionName = this.fromApiJsonHelper.extractStringNamed(actionNameParamName, eventElement); - final HookResource event = HookResource.createNewWithoutHook(entityName, actionName); - allEvents.add(event); - } - - return allEvents; - } - - private void validateHookRules(final HookTemplate template, final Set config, Set events) { - - final List dataValidationErrors = new ArrayList<>(); - final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("hook"); - - if (!template.getName().equalsIgnoreCase(webTemplateName) && this.hookRepository.findOneByTemplateId(template.getId()) != null) { - final String errorMessage = "multiple.non.web.template.hooks.not.supported"; - baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); - } - - for (final HookConfiguration conf : config) { - final String fieldValue = conf.getFieldValue(); - if (conf.getFieldName().equals(contentTypeName)) { - if ((!fieldValue.equalsIgnoreCase("json") && !fieldValue.equalsIgnoreCase("form"))) { - final String errorMessage = "content.type.must.be.json.or.form"; - baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); - } - } - - if (conf.getFieldName().equals(payloadURLName)) { - try { - final WebHookService service = processorHelper.createWebHookService(fieldValue); - service.sendEmptyRequest().execute(); - } catch (IOException re) { - String errorMessage = "url.invalid"; - baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); - } - } - } - - if (events == null || events.isEmpty()) { - final String errorMessage = "registered.events.cannot.be.empty"; - baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(errorMessage); - } - - final Set fields = template.getFields(); - for (final Schema field : fields) { - if (!field.isOptional()) { - boolean found = false; - for (final HookConfiguration conf : config) { - if (field.getFieldName().equals(conf.getFieldName())) { - found = true; - } - } - if (!found) { - final String errorMessage = "required.config.field." + "not.provided"; - baseDataValidator.reset().value(field.getFieldName()).failWithCodeNoParameterAddedToErrorCode(errorMessage); - } - } - } - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException(dataValidationErrors); - } - } - - private void handleHookDataIntegrityIssues(final JsonCommand command, final Throwable realCause, final Exception dve) { - if (realCause.getMessage().contains("hook_name")) { - final String name = command.stringValueOfParameterNamed("name"); - throw new PlatformDataIntegrityException("error.msg.hook.duplicate.name", "A hook with name '" + name + "' already exists", - "name", name); - } - throw ErrorHandler.getMappable(dve, "error.msg.unknown.data.integrity.issue", - "Unknown data integrity issue with resource: " + realCause.getMessage()); - } -} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java index 262ea5f43df..8de23cadc06 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -241,7 +241,7 @@ public String retrieveTemplate(@Context final UriInfo uriInfo, this.context.authenticatedUser().validateHasReadPermission(PRODUCTMIX); final Collection productOptions = this.loanProductReadPlatformService.retrieveAvailableLoanProductsForMix(); - final ProductMixData productMixData = ProductMixData.template(productOptions); + final ProductMixData productMixData = ProductMixData.builder().productOptions(productOptions).build(); return this.productMixDataApiJsonSerializer.serialize(settings, productMixData, PRODUCT_MIX_DATA_PARAMETERS); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/api/ProductMixApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/api/ProductMixApiResource.java index 3ca3ff66fc0..4a1635d54ac 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/api/ProductMixApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/api/ProductMixApiResource.java @@ -57,20 +57,22 @@ @RequiredArgsConstructor public class ProductMixApiResource { - private final CommandDispatcher commandDispatcher; private final ProductMixReadPlatformService productMixReadPlatformService; private final LoanProductReadPlatformService loanProductReadPlatformService; + private final CommandDispatcher commandDispatcher; @GET @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Retrieve Product Mix Template", operationId = "retrieveTemplateProductMix") public ProductMixData retrieveTemplate(@PathParam("productId") final Long productId, @Context final UriInfo uriInfo) { - ProductMixData productMixData = this.productMixReadPlatformService.retrieveLoanProductMixDetails(productId); + var productMixData = productMixReadPlatformService.retrieveLoanProductMixDetails(productId); if (uriInfo.getQueryParameters().containsKey("template")) { final Collection productOptions = this.loanProductReadPlatformService.retrieveAvailableLoanProductsForMix(); - productMixData = ProductMixData.withTemplateOptions(productMixData, productOptions); + productMixData = ProductMixData.builder().productId(productMixData.getProductId()).productName(productMixData.getProductName()) + .restrictedProducts(productMixData.getRestrictedProducts()).allowedProducts(productMixData.getAllowedProducts()) + .productOptions(productOptions).build(); } return productMixData; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateRequest.java index a8de2b72bef..315dcb4ca3f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateRequest.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateRequest.java @@ -24,9 +24,15 @@ import java.io.Serial; import java.io.Serializable; import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; +@Builder @Data +@NoArgsConstructor +@AllArgsConstructor public class ProductMixCreateRequest implements Serializable { @Serial diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateResponse.java index ce3d7a1cb97..f59bba64a97 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateResponse.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixCreateResponse.java @@ -21,15 +21,15 @@ import java.io.Serial; import java.io.Serializable; import java.util.Map; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.extern.jackson.Jacksonized; -import org.apache.fineract.commands.annotation.CommandType; +import lombok.NoArgsConstructor; -@Data @Builder -@Jacksonized -@CommandType(entity = "PRODUCTMIX", action = "CREATE") +@Data +@NoArgsConstructor +@AllArgsConstructor public class ProductMixCreateResponse implements Serializable { @Serial diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixData.java index 8bb7a02a0b4..96c76a55b3f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixData.java @@ -18,37 +18,27 @@ */ package org.apache.fineract.portfolio.loanproduct.productmix.data; +import java.io.Serial; import java.io.Serializable; import java.util.Collection; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; +@Builder @Data +@NoArgsConstructor +@AllArgsConstructor public class ProductMixData implements Serializable { - private final Long productId; - private final String productName; - private final Collection restrictedProducts; - private final Collection allowedProducts; - private final Collection productOptions; + @Serial + private static final long serialVersionUID = 1L; - public static ProductMixData template(final Collection productOptions) { - return new ProductMixData(null, null, null, null, productOptions); - } - - public static ProductMixData withTemplateOptions(final ProductMixData productMixData, - final Collection productOptions) { - return new ProductMixData(productMixData.productId, productMixData.productName, productMixData.restrictedProducts, - productMixData.allowedProducts, productOptions); - } - - public static ProductMixData withDetails(final Long productId, final String productName, - final Collection restrictedProducts, final Collection allowedProducts) { - return new ProductMixData(productId, productName, restrictedProducts, allowedProducts, null); - } - - public static ProductMixData withRestrictedOptions(final Collection restrictedProducts, - final Collection allowedProducts) { - return new ProductMixData(null, null, restrictedProducts, allowedProducts, null); - } + private Long productId; + private String productName; + private Collection restrictedProducts; + private Collection allowedProducts; + private Collection productOptions; } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteRequest.java index 39fa656744b..16915e15dae 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteRequest.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteRequest.java @@ -22,13 +22,15 @@ import jakarta.validation.constraints.Positive; import java.io.Serial; import java.io.Serializable; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.extern.jackson.Jacksonized; +import lombok.NoArgsConstructor; -@Data @Builder -@Jacksonized +@Data +@NoArgsConstructor +@AllArgsConstructor public class ProductMixDeleteRequest implements Serializable { @Serial diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteResponse.java index 05911da3771..411800cbffa 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteResponse.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixDeleteResponse.java @@ -21,15 +21,15 @@ import java.io.Serial; import java.io.Serializable; import java.util.Map; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.extern.jackson.Jacksonized; -import org.apache.fineract.commands.annotation.CommandType; +import lombok.NoArgsConstructor; -@Data @Builder -@Jacksonized -@CommandType(entity = "PRODUCTMIX", action = "DELETE") +@Data +@NoArgsConstructor +@AllArgsConstructor public class ProductMixDeleteResponse implements Serializable { @Serial diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateRequest.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateRequest.java index 70a4145bb3f..684b49fd8f7 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateRequest.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateRequest.java @@ -23,9 +23,15 @@ import java.io.Serial; import java.io.Serializable; import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; +import lombok.NoArgsConstructor; +@Builder @Data +@NoArgsConstructor +@AllArgsConstructor public class ProductMixUpdateRequest implements Serializable { @Serial diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateResponse.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateResponse.java index f0971fa12ce..40f06b3d380 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateResponse.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/data/ProductMixUpdateResponse.java @@ -21,15 +21,15 @@ import java.io.Serial; import java.io.Serializable; import java.util.Map; +import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; -import lombok.extern.jackson.Jacksonized; -import org.apache.fineract.commands.annotation.CommandType; +import lombok.NoArgsConstructor; -@Data @Builder -@Jacksonized -@CommandType(entity = "PRODUCTMIX", action = "UPDATE") +@Data +@NoArgsConstructor +@AllArgsConstructor public class ProductMixUpdateResponse implements Serializable { @Serial diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/service/ProductMixReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/service/ProductMixReadPlatformServiceImpl.java index ad6c90d11fe..bdbf2a9700c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/service/ProductMixReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/productmix/service/ProductMixReadPlatformServiceImpl.java @@ -106,7 +106,8 @@ public Map extractData(final ResultSet rs) throws SQLExcep .retrieveRestrictedProductsForMix(this.productId); final Collection allowedProducts = this.loanProductReadPlatformService .retrieveAllowedProductsForMix(this.productId); - final ProductMixData productMixData = ProductMixData.withRestrictedOptions(restrictedProducts, allowedProducts); + final ProductMixData productMixData = ProductMixData.builder().restrictedProducts(restrictedProducts) + .allowedProducts(allowedProducts).build(); extractedData.put(this.productId, productMixData); return extractedData; } @@ -117,7 +118,8 @@ public Map extractData(final ResultSet rs) throws SQLExcep .retrieveRestrictedProductsForMix(productId); final Collection allowedProducts = this.loanProductReadPlatformService .retrieveAllowedProductsForMix(productId); - final ProductMixData productMixData = ProductMixData.withDetails(productId, name, restrictedProducts, allowedProducts); + final ProductMixData productMixData = ProductMixData.builder().productId(productId).productName(name) + .restrictedProducts(restrictedProducts).allowedProducts(allowedProducts).build(); extractedData.put(productId, productMixData); } while (rs.next()); return extractedData; diff --git a/fineract-provider/src/main/resources/jpa/static-weaving/module/fineract-provider/persistence.xml b/fineract-provider/src/main/resources/jpa/static-weaving/module/fineract-provider/persistence.xml index e33a8cf02e8..6513bac95d3 100644 --- a/fineract-provider/src/main/resources/jpa/static-weaving/module/fineract-provider/persistence.xml +++ b/fineract-provider/src/main/resources/jpa/static-weaving/module/fineract-provider/persistence.xml @@ -201,7 +201,7 @@ org.apache.fineract.infrastructure.hooks.domain.HookConfiguration org.apache.fineract.infrastructure.hooks.domain.HookResource org.apache.fineract.infrastructure.hooks.domain.HookTemplate - org.apache.fineract.infrastructure.hooks.domain.Schema + org.apache.fineract.infrastructure.hooks.domain.HookSchema org.apache.fineract.infrastructure.jobs.domain.JobParameter org.apache.fineract.infrastructure.jobs.domain.ScheduledJobDetail org.apache.fineract.infrastructure.jobs.domain.ScheduledJobRunHistory