DevfileService extends Service { @GET @Path("search") @Produces(APPLICATION_JSON) @ApiOperation( value = "Get devfiles which user can read", notes = "This operation can be performed only by authorized user. " + "It is possible to add additional constraints for the desired devfiles by specifying\n" + "multiple query parameters that is representing fields of the devfile. All constrains\n" + "would be combined with \"And\" condition. Also, it is possible to specify 'like:' prefix\n" + "for the query parameters. In this case instead of an exact match would be used SQL pattern like search.\n" + "Examples id=sdfsdf5&devfile.meta.name=like:%dfdf&", response = UserDevfileDto.class, responseContainer = "List") @ApiResponses({ @ApiResponse(code = 200, message = "The devfiles successfully fetched"), @ApiResponse(code = 500, message = "Internal server error occurred during devfiles fetching") }) public Response getUserDevfiles( @ApiParam("The number of the items to skip") @DefaultValue("0") @QueryParam("skipCount") Integer skipCount, @ApiParam("The limit of the items in the response, default is 30, maximum 60") @DefaultValue("30") @QueryParam("maxItems") Integer maxItems, @ApiParam( "A list of fields and directions of sort. By default items would be sorted by id. Example id:asc,name:desc.") @QueryParam("order") String order) throws ServerException, BadRequestException { final Set<String> skip = ImmutableSet.of("token", "skipCount", "maxItems", "order"); Map<String, Set<String>> queryParams = URLEncodedUtils.parse(uriInfo.getRequestUri()); final List<Pair<String, String>> query = queryParams .entrySet() .stream() .filter(param -> !param.getValue().isEmpty()) .filter(param -> !skip.contains(param.getKey())) .map(entry -> Pair.of(entry.getKey(), entry.getValue().iterator().next())) .collect(toList()); List<Pair<String, String>> searchOrder = Collections.emptyList(); if (order != null && !order.isEmpty()) { try { searchOrder = Splitter.on(",") .trimResults() .omitEmptyStrings() .withKeyValueSeparator(":") .split(order) .entrySet() .stream() .map(e -> Pair.of(e.getKey(), e.getValue())) .collect(toList()); } catch (IllegalArgumentException e) { throw new BadRequestException("Invalid `order` query parameter format." + e.getMessage()); } } Page<? extends UserDevfile> userDevfilesPage = userDevfileManager.getUserDevfiles(maxItems, skipCount, query, searchOrder); List<UserDevfileDto> list = userDevfilesPage .getItems() .stream() .map(DtoConverter::asDto) .map(dto -> linksInjector.injectLinks(asDto(dto), getServiceContext())) .collect(toList()); return Response.ok().entity(list).header("Link", createLinkHeader(userDevfilesPage)).build(); } @Inject  DevfileService(
      DevfileSchemaProvider schemaCachedProvider,
      UserDevfileManager userDevfileManager,
      DevfileServiceLinksInjector linksInjector); @GET @Produces(APPLICATION_JSON) @ApiOperation(value = "Retrieves current version of devfile JSON schema") @ApiResponses({ @ApiResponse(code = 200, message = "The schema successfully retrieved"), @ApiResponse(code = 500, message = "Internal server error occurred") }) Response getSchema(); @Path("/devfile") @POST @Consumes({APPLICATION_JSON, "text/yaml", "text/x-yaml"}) @Produces(APPLICATION_JSON) @ApiOperation( value = "Creates a new persistent Devfile from yaml representation", consumes = "application/json, text/yaml, text/x-yaml", produces = APPLICATION_JSON, nickname = "createFromDevfileYaml", response = UserDevfileDto.class) @ApiResponses({ @ApiResponse(code = 201, message = "The devfile successfully created"), @ApiResponse(code = 400, message = "Missed required parameters, parameters are not valid"), @ApiResponse(code = 403, message = "The user does not have access to create a new devfile"), @ApiResponse(code = 409, message = "Conflict error occurred during the devfile creation"), @ApiResponse(code = 500, message = "Internal server error occurred") }) Response createFromDevfileYaml(
      @ApiParam(value = "The devfile to create", required = true) DevfileDto devfile); @POST @Consumes({APPLICATION_JSON}) @Produces(APPLICATION_JSON) @ApiOperation( value = "Creates a new persistent Devfile", consumes = "application/json", produces = APPLICATION_JSON, nickname = "create", response = UserDevfileDto.class) @ApiResponses({ @ApiResponse(code = 201, message = "The devfile successfully created"), @ApiResponse(code = 400, message = "Missed required parameters, parameters are not valid"), @ApiResponse(code = 403, message = "The user does not have access to create a new devfile"), @ApiResponse( code = 409, message = "Conflict error occurred during the devfile creation" + "(e.g. The devfile with such name already exists)"), @ApiResponse(code = 500, message = "Internal server error occurred") }) Response createFromUserDevfile(
      @ApiParam(value = "The devfile to create", required = true) UserDevfileDto userDevfileDto); @GET @Path("/{id}") @Produces(APPLICATION_JSON) @ApiOperation(value = "Get devfile by its identifier") @ApiResponses({ @ApiResponse(code = 200, message = "The response contains requested workspace entity"), @ApiResponse(code = 404, message = "The devfile with specified id does not exist"), @ApiResponse(code = 403, message = "The user is not allowed to read devfile"), @ApiResponse(code = 500, message = "Internal server error occurred") }) UserDevfileDto getById(
      @ApiParam(value = "UserDevfile identifier") @PathParam("id") String id); @GET @Path("search") @Produces(APPLICATION_JSON) @ApiOperation( value = "Get devfiles which user can read", notes = "This operation can be performed only by authorized user. " + "It is possible to add additional constraints for the desired devfiles by specifying\n" + "multiple query parameters that is representing fields of the devfile. All constrains\n" + "would be combined with \"And\" condition. Also, it is possible to specify 'like:' prefix\n" + "for the query parameters. In this case instead of an exact match would be used SQL pattern like search.\n" + "Examples id=sdfsdf5&devfile.meta.name=like:%dfdf&", response = UserDevfileDto.class, responseContainer = "List") @ApiResponses({ @ApiResponse(code = 200, message = "The devfiles successfully fetched"), @ApiResponse(code = 500, message = "Internal server error occurred during devfiles fetching") }) Response getUserDevfiles(
      @ApiParam("The number of the items to skip") @DefaultValue("0") @QueryParam("skipCount")
          Integer skipCount,
      @ApiParam("The limit of the items in the response, default is 30, maximum 60")
          @DefaultValue("30")
          @QueryParam("maxItems")
          Integer maxItems,
      @ApiParam(
              "A list of fields and directions of sort. By default items would be sorted by id. Example id:asc,name:desc.")
          @QueryParam("order")
          String order); @PUT @Path("/{id}") @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @ApiOperation(value = "Update the devfile by replacing all the existing data with update") @ApiResponses({ @ApiResponse(code = 200, message = "The devfile successfully updated"), @ApiResponse(code = 400, message = "Missed required parameters, parameters are not valid"), @ApiResponse(code = 403, message = "The user does not have access to update the devfile"), @ApiResponse( code = 409, message = "Conflict error occurred during devfile update" + "(e.g. Workspace with such name already exists)"), @ApiResponse(code = 500, message = "Internal server error occurred") }) UserDevfileDto update(
      @ApiParam("The devfile id") @PathParam("id") String id,
      @ApiParam(value = "The devfile update", required = true) UserDevfileDto update); @DELETE @Path("/{id}") @ApiOperation(value = "Removes the devfile") @ApiResponses({ @ApiResponse(code = 204, message = "The devfile successfully removed"), @ApiResponse(code = 403, message = "The user does not have access to remove the devfile"), @ApiResponse(code = 500, message = "Internal server error occurred") }) void delete(@ApiParam("The devfile id") @PathParam("id") String id);  }
@Test public void shouldGetUserDevfilesAvailableToUser() throws Exception { final UserDevfileDto devfileDto = TestObjectGenerator.createUserDevfileDto(); final UserDevfileImpl userDevfileImpl = new UserDevfileImpl(devfileDto, TEST_ACCOUNT); doReturn(new Page<>(ImmutableList.of(userDevfileImpl), 0, 1, 1)) .when(userDevfileManager) .getUserDevfiles(anyInt(), anyInt(), anyList(), anyList()); final Response response = given() .auth() .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) .contentType("application/json") .when() .expect() .statusCode(200) .get(SECURE_PATH + "/devfile/search"); final List<UserDevfileDto> res = unwrapDtoList(response, UserDevfileDto.class); assertEquals(res.size(), 1); assertEquals(res.get(0).withLinks(emptyList()), devfileDto); verify(userDevfileManager).getUserDevfiles(eq(30), eq(0), anyList(), anyList()); }
@Test public void shouldBeAbleToSetLimitAndOffsetOnUserDevfileSearch() throws Exception { doReturn(new Page<>(Collections.emptyList(), 0, 1, 0)) .when(userDevfileManager) .getUserDevfiles(anyInt(), anyInt(), anyList(), anyList()); final Response response = given() .auth() .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) .contentType("application/json") .queryParam("maxItems", 5) .queryParam("skipCount", 52) .when() .expect() .statusCode(200) .get(SECURE_PATH + "/devfile/search"); verify(userDevfileManager).getUserDevfiles(eq(5), eq(52), anyList(), anyList()); }
@Test public void shouldBeAbleToSetFiltertOnUserDevfileSearch() throws Exception { doReturn(new Page<>(Collections.emptyList(), 0, 1, 0)) .when(userDevfileManager) .getUserDevfiles(anyInt(), anyInt(), anyList(), anyList()); Map<String, String> parameters = ImmutableMap.of("id", "sdfsdf5", "devfile.meta.name", "like:%dfdf"); final Response response = given() .auth() .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) .contentType("application/json") .queryParameter("id", "sdfsdf5") .queryParameter("devfile.meta.name", "like:%dfdf") .when() .expect() .statusCode(200) .get(SECURE_PATH + "/devfile/search"); Class<List<Pair<String, String>>> listClass = (Class<List<Pair<String, String>>>) (Class) ArrayList.class; ArgumentCaptor<List<Pair<String, String>>> filterCaptor = ArgumentCaptor.forClass(listClass); verify(userDevfileManager).getUserDevfiles(eq(30), eq(0), filterCaptor.capture(), anyList()); assertEquals( filterCaptor.getValue(), ImmutableList.of(new Pair("devfile.meta.name", "like:%dfdf"), new Pair("id", "sdfsdf5"))); }
@Test public void shouldBeAbleToSetOrderOnUserDevfileSearch() throws Exception { doReturn(new Page<>(Collections.emptyList(), 0, 1, 0)) .when(userDevfileManager) .getUserDevfiles(anyInt(), anyInt(), anyList(), anyList()); final Response response = given() .auth() .basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD) .contentType("application/json") .queryParameter("order", "id:asc,name:desc") .when() .expect() .statusCode(200) .get(SECURE_PATH + "/devfile/search"); Class<List<Pair<String, String>>> listClass = (Class<List<Pair<String, String>>>) (Class) ArrayList.class; ArgumentCaptor<List<Pair<String, String>>> orderCaptor = ArgumentCaptor.forClass(listClass); verify(userDevfileManager).getUserDevfiles(eq(30), eq(0), anyList(), orderCaptor.capture()); assertEquals( orderCaptor.getValue(), ImmutableList.of(new Pair("id", "asc"), new Pair("name", "desc"))); }