Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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<String> RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(nameParamName, displayNameParamName,
templateIdParamName, isActiveParamName, configParamName, eventsParamName, templateNameParamName));

public static final Set<String> UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(nameParamName, displayNameParamName,
templateIdParamName, isActiveParamName, configParamName, eventsParamName, templateNameParamName));

}
Original file line number Diff line number Diff line change
Expand Up @@ -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<HookData> 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<HookData> 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<HookData> 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<HookCreateResponse> 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<HookUpdateResponse> 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<HookDeleteResponse> response = dispatcher.dispatch(command);

return this.toApiJsonSerializer.serialize(result);
return response.get();
}

}
Loading
Loading