mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
Add pagination and search by name capabilities to WorkflowsResource
Closes #44164 Signed-off-by: Stefan Guilhen <sguilhen@redhat.com>
This commit is contained in:
parent
84a679224b
commit
7acf2ceccb
@ -9,6 +9,7 @@ import jakarta.ws.rs.POST;
|
||||
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.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
@ -35,6 +36,15 @@ public interface WorkflowsResource {
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<WorkflowRepresentation> list();
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
List<WorkflowRepresentation> list(
|
||||
@QueryParam("search") String search,
|
||||
@QueryParam("exact") Boolean exact,
|
||||
@QueryParam("first") Integer firstResult,
|
||||
@QueryParam("max") Integer maxResults
|
||||
);
|
||||
|
||||
@Path("{id}")
|
||||
WorkflowResource workflow(@PathParam("id") String id);
|
||||
}
|
||||
|
||||
@ -17,10 +17,12 @@
|
||||
|
||||
package org.keycloak.models.workflow;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.representations.workflows.WorkflowRepresentation;
|
||||
import org.keycloak.utils.StringUtil;
|
||||
|
||||
public interface WorkflowProvider extends Provider {
|
||||
|
||||
@ -40,6 +42,17 @@ public interface WorkflowProvider extends Provider {
|
||||
|
||||
Stream<Workflow> getWorkflows();
|
||||
|
||||
default Stream<Workflow> getWorkflows(String search, Boolean exact, Integer first, Integer max) {
|
||||
return getWorkflows().sorted(Comparator.comparing(Workflow::getName))
|
||||
.filter(workflow -> {
|
||||
if (StringUtil.isBlank(search)) {
|
||||
return true;
|
||||
}
|
||||
return Boolean.TRUE.equals(exact) ? workflow.getName().equals(search) : workflow.getName().toLowerCase().contains(search.toLowerCase());
|
||||
})
|
||||
.skip(first).limit(max);
|
||||
}
|
||||
|
||||
WorkflowRepresentation toRepresentation(Workflow workflow);
|
||||
|
||||
void updateWorkflow(Workflow workflow, WorkflowRepresentation rep);
|
||||
|
||||
@ -5,14 +5,17 @@ import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.jakarta.rs.yaml.YAMLMediaTypes;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.DefaultValue;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.NotFoundException;
|
||||
import jakarta.ws.rs.POST;
|
||||
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.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.Profile.Feature;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
@ -79,9 +82,16 @@ public class WorkflowsResource {
|
||||
|
||||
@GET
|
||||
@Produces({MediaType.APPLICATION_JSON, YAMLMediaTypes.APPLICATION_JACKSON_YAML})
|
||||
public List<WorkflowRepresentation> list() {
|
||||
public List<WorkflowRepresentation> list(
|
||||
@Parameter(description = "A String representing the workflow name - either partial or exact") @QueryParam("search") String search,
|
||||
@Parameter(description = "Boolean which defines whether the param 'search' must match exactly or not") @QueryParam("exact") Boolean exact,
|
||||
@Parameter(description = "The position of the first result to be processed (pagination offset)") @QueryParam("first") @DefaultValue("0") Integer firstResult,
|
||||
@Parameter(description = "The maximum number of results to be returned - defaults to 10") @QueryParam("max") @DefaultValue("10") Integer maxResults
|
||||
) {
|
||||
auth.realm().requireManageRealm();
|
||||
|
||||
return provider.getWorkflows().map(provider::toRepresentation).toList();
|
||||
int first = Optional.ofNullable(firstResult).orElse(0);
|
||||
int max = Optional.ofNullable(maxResults).orElse(10);
|
||||
return provider.getWorkflows(search, exact, first, max).map(provider::toRepresentation).toList();
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,6 +264,47 @@ public class WorkflowManagementTest extends AbstractWorkflowTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() {
|
||||
// create a few workflows with different names
|
||||
String[] workflowNames = {"alpha-workflow", "beta-workflow", "gamma-workflow", "delta-workflow"};
|
||||
for (String name : workflowNames) {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName(name)
|
||||
.onEvent(ResourceOperationType.USER_ADDED.toString())
|
||||
.withSteps(
|
||||
WorkflowStepRepresentation.create().of(NotifyUserStepProviderFactory.ID)
|
||||
.after(Duration.ofDays(5))
|
||||
.build()
|
||||
).build()).close();
|
||||
}
|
||||
|
||||
// use the API to search for workflows by name, both partial and exact matches
|
||||
WorkflowsResource workflows = managedRealm.admin().workflows();
|
||||
List<WorkflowRepresentation> representations = workflows.list("alpha", false, null, null);
|
||||
assertThat(representations, Matchers.hasSize(1));
|
||||
assertThat(representations.get(0).getName(), is("alpha-workflow"));
|
||||
|
||||
representations = workflows.list("workflow", false, null, null);
|
||||
assertThat(representations, Matchers.hasSize(4));
|
||||
representations = workflows.list("beta-workflow", true, null, null);
|
||||
assertThat(representations, Matchers.hasSize(1));
|
||||
assertThat(representations.get(0).getName(), is("beta-workflow"));
|
||||
representations = workflows.list("nonexistent", false, null, null);
|
||||
assertThat(representations, Matchers.hasSize(0));
|
||||
|
||||
// test pagination parameters
|
||||
representations = workflows.list(null, null, 1, 2);
|
||||
assertThat(representations, Matchers.hasSize(2));
|
||||
// returned workflows should be ordered by name
|
||||
assertThat(representations.get(0).getName(), is("beta-workflow"));
|
||||
assertThat(representations.get(1).getName(), is("delta-workflow"));
|
||||
|
||||
representations = workflows.list("gamma", false, 0, 10);
|
||||
assertThat(representations, Matchers.hasSize(1));
|
||||
assertThat(representations.get(0).getName(), is("gamma-workflow"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWorkflowDoesNotFallThroughStepsInSingleRun() {
|
||||
managedRealm.admin().workflows().create(WorkflowRepresentation.withName("myworkflow")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user