Commit 36e9b494 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

API endpoint for listing backgrounds

parent a79d4005
...@@ -10,9 +10,14 @@ import org.apache.logging.log4j.Logger; ...@@ -10,9 +10,14 @@ import org.apache.logging.log4j.Logger;
import org.hibernate.annotations.Cascade; import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType; import org.hibernate.annotations.CascadeType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lcsb.mapviewer.common.exception.NotImplementedException; import lcsb.mapviewer.common.exception.NotImplementedException;
import lcsb.mapviewer.model.Project; import lcsb.mapviewer.model.Project;
import lcsb.mapviewer.model.user.User; import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.modelutils.serializer.ProjectAsIdSerializer;
import lcsb.mapviewer.modelutils.serializer.UserAsIdSerializer;
/** /**
* This object represents type of visualization for the model. * This object represents type of visualization for the model.
...@@ -67,6 +72,7 @@ public class ProjectBackground implements Serializable { ...@@ -67,6 +72,7 @@ public class ProjectBackground implements Serializable {
/** /**
* Does the layout present data in hierarchical view. * Does the layout present data in hierarchical view.
*/ */
@JsonIgnore
private boolean hierarchicalView = false; private boolean hierarchicalView = false;
/** /**
...@@ -74,18 +80,18 @@ public class ProjectBackground implements Serializable { ...@@ -74,18 +80,18 @@ public class ProjectBackground implements Serializable {
* level. This parameter defines the level at which it's fixed or contains null * level. This parameter defines the level at which it's fixed or contains null
* if it's general hierarchical view. * if it's general hierarchical view.
*/ */
@JsonIgnore
private Integer hierarchyViewLevel; private Integer hierarchyViewLevel;
/** /**
* Project to which this data overlay is assigned. * Project to which this data overlay is assigned.
*/ */
@ManyToOne(fetch = FetchType.LAZY, optional = false) @ManyToOne(fetch = FetchType.LAZY, optional = false)
@JsonSerialize(using = ProjectAsIdSerializer.class)
private Project project; private Project project;
/**
* Who created the layout.
*/
@ManyToOne(fetch = FetchType.LAZY, optional = false) @ManyToOne(fetch = FetchType.LAZY, optional = false)
@JsonSerialize(using = UserAsIdSerializer.class)
private User creator; private User creator;
/** /**
...@@ -104,7 +110,7 @@ public class ProjectBackground implements Serializable { ...@@ -104,7 +110,7 @@ public class ProjectBackground implements Serializable {
/** /**
* List of image folders for generated background images. * List of image folders for generated background images.
*/ */
@Cascade({ CascadeType.SAVE_UPDATE}) @Cascade({ CascadeType.SAVE_UPDATE })
@OneToMany(fetch = FetchType.LAZY, mappedBy = "projectBackground", orphanRemoval = true) @OneToMany(fetch = FetchType.LAZY, mappedBy = "projectBackground", orphanRemoval = true)
private Set<ProjectBackgroundImageLayer> backgrounds = new HashSet<>(); private Set<ProjectBackgroundImageLayer> backgrounds = new HashSet<>();
...@@ -146,7 +152,8 @@ public class ProjectBackground implements Serializable { ...@@ -146,7 +152,8 @@ public class ProjectBackground implements Serializable {
this.hierarchyViewLevel = layout.hierarchyViewLevel; this.hierarchyViewLevel = layout.hierarchyViewLevel;
this.orderIndex = layout.orderIndex; this.orderIndex = layout.orderIndex;
for (ProjectBackgroundImageLayer dataOverlayImageLayer : layout.getProjectBackgroundImageLayer()) { for (ProjectBackgroundImageLayer dataOverlayImageLayer : layout.getProjectBackgroundImageLayer()) {
ProjectBackgroundImageLayer dataOverlayImageLayerCopy = new ProjectBackgroundImageLayer(dataOverlayImageLayer.getModel(), ProjectBackgroundImageLayer dataOverlayImageLayerCopy = new ProjectBackgroundImageLayer(
dataOverlayImageLayer.getModel(),
dataOverlayImageLayer.getDirectory()); dataOverlayImageLayer.getDirectory());
this.addProjectBackgroundImageLayer(dataOverlayImageLayerCopy); this.addProjectBackgroundImageLayer(dataOverlayImageLayerCopy);
} }
......
...@@ -10,8 +10,12 @@ import org.apache.logging.log4j.Logger; ...@@ -10,8 +10,12 @@ import org.apache.logging.log4j.Logger;
import org.hibernate.annotations.OnDelete; import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction; import org.hibernate.annotations.OnDeleteAction;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.Model;
import lcsb.mapviewer.model.map.model.ModelData; import lcsb.mapviewer.model.map.model.ModelData;
import lcsb.mapviewer.modelutils.serializer.ModelDataAsIdSerializer;
import lcsb.mapviewer.modelutils.serializer.ProjectBackgroundAsIdSerializer;
/** /**
* This object represents set of images generated for background visualization * This object represents set of images generated for background visualization
...@@ -55,9 +59,10 @@ public class ProjectBackgroundImageLayer implements Serializable { ...@@ -55,9 +59,10 @@ public class ProjectBackgroundImageLayer implements Serializable {
/** /**
* {@link ModelData} for which the images were created. * {@link ModelData} for which the images were created.
*/ */
@ManyToOne(fetch = FetchType.LAZY, optional=false) @ManyToOne(optional = false)
@JoinColumn(name="model_id", updatable=false) @JoinColumn(name = "model_id", updatable = false)
@OnDelete(action = OnDeleteAction.CASCADE) @OnDelete(action = OnDeleteAction.CASCADE)
@JsonSerialize(using = ModelDataAsIdSerializer.class)
private ModelData model; private ModelData model;
/** /**
...@@ -65,6 +70,7 @@ public class ProjectBackgroundImageLayer implements Serializable { ...@@ -65,6 +70,7 @@ public class ProjectBackgroundImageLayer implements Serializable {
*/ */
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)
@OnDelete(action = OnDeleteAction.CASCADE) @OnDelete(action = OnDeleteAction.CASCADE)
@JsonSerialize(using = ProjectBackgroundAsIdSerializer.class)
private ProjectBackground projectBackground; private ProjectBackground projectBackground;
/** /**
......
package lcsb.mapviewer.modelutils.serializer;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lcsb.mapviewer.model.map.model.ModelData;
public class ModelDataAsIdSerializer extends JsonSerializer<ModelData> {
@Override
public void serialize(final ModelData model, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeNumberField("id", model.getId());
gen.writeEndObject();
}
}
\ No newline at end of file
package lcsb.mapviewer.modelutils.serializer;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lcsb.mapviewer.model.Project;
public class ProjectAsIdSerializer extends JsonSerializer<Project> {
@Override
public void serialize(final Project project, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("projectId", project.getProjectId());
gen.writeEndObject();
}
}
\ No newline at end of file
package lcsb.mapviewer.modelutils.serializer;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lcsb.mapviewer.model.map.layout.ProjectBackground;
public class ProjectBackgroundAsIdSerializer extends JsonSerializer<ProjectBackground> {
@Override
public void serialize(final ProjectBackground background, final JsonGenerator gen,
final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeNumberField("id", background.getId());
gen.writeEndObject();
}
}
\ No newline at end of file
package lcsb.mapviewer.modelutils.serializer;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import lcsb.mapviewer.model.user.User;
public class UserAsIdSerializer extends JsonSerializer<User> {
@Override
public void serialize(final User user, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("login", user.getLogin());
gen.writeEndObject();
}
}
\ No newline at end of file
...@@ -3,20 +3,21 @@ package lcsb.mapviewer.api.projects; ...@@ -3,20 +3,21 @@ package lcsb.mapviewer.api.projects;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PostFilter; import org.springframework.security.access.prepost.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import lcsb.mapviewer.api.*; import lcsb.mapviewer.api.*;
import lcsb.mapviewer.model.cache.FileEntry; import lcsb.mapviewer.model.cache.FileEntry;
import lcsb.mapviewer.model.map.layout.ProjectBackground;
import lcsb.mapviewer.model.security.PrivilegeType; import lcsb.mapviewer.model.security.PrivilegeType;
import lcsb.mapviewer.model.user.User; import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.services.ObjectNotFoundException; import lcsb.mapviewer.services.ObjectNotFoundException;
...@@ -159,6 +160,46 @@ public class ProjectController extends BaseController { ...@@ -159,6 +160,46 @@ public class ProjectController extends BaseController {
throws QueryException { throws QueryException {
return projectController.getSubmapConnections(projectId); return projectController.getSubmapConnections(projectId);
} }
@PreAuthorize("hasAnyAuthority('IS_ADMIN', 'READ_PROJECT:' + #projectId) "
+ "or not @projectService.projectExists(#projectId)")
@GetMapping(value = "/{projectId}/backgrounds/")
public List<ProjectBackground> getBackgrounds(
@PathVariable(value = "projectId") String projectId)
throws lcsb.mapviewer.services.ObjectNotFoundException {
return projectController.getBackgrounds(projectId);
}
@PreAuthorize("hasAnyAuthority('IS_ADMIN', 'READ_PROJECT:' + #projectId) "
+ "or not @projectService.projectExists(#projectId)")
@GetMapping(value = "/{projectId}/backgrounds/{backgroundId}")
public ProjectBackground getBackgroundById(
@PathVariable(value = "projectId") String projectId,
@PathVariable(value = "backgroundId") Integer backgroundId) throws QueryException {
return projectController.getBackgroundById(projectId, backgroundId);
}
@PreAuthorize("hasAuthority('IS_ADMIN')" +
"or hasAuthority('IS_CURATOR') and hasAuthority('WRITE_PROJECT:' + #projectId)")
@DeleteMapping(value = "/{projectId}/backgrounds/{backgroundId}")
public Map<String, Object> removeBackground(
@PathVariable(value = "projectId") String projectId,
@PathVariable(value = "backgroundId") Integer backgroundId) throws QueryException, IOException {
return projectController.removeBackground(projectId, backgroundId);
}
@PreAuthorize("hasAuthority('IS_ADMIN')" +
" or hasAuthority('IS_CURATOR') and hasAuthority('WRITE_PROJECT:' + #projectId)")
@PatchMapping(value = "/{projectId}/backgrounds/{backgroundId}")
public ProjectBackground updateBackground(
@RequestBody String body,
@PathVariable(value = "overlayId") Integer overlayId,
@PathVariable(value = "backgroundId") String projectId)
throws QueryException, IOException {
Map<String, Object> node = parseBody(body);
Map<String, Object> data = getData(node, "overlay");
return projectController.updateOverlay(projectId, overlayId, data);
}
public ServletContext getContext() { public ServletContext getContext() {
return context; return context;
......
...@@ -9,6 +9,7 @@ import java.util.*; ...@@ -9,6 +9,7 @@ import java.util.*;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.hibernate.Hibernate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
...@@ -28,6 +29,7 @@ import lcsb.mapviewer.model.cache.FileEntry; ...@@ -28,6 +29,7 @@ import lcsb.mapviewer.model.cache.FileEntry;
import lcsb.mapviewer.model.cache.UploadedFileEntry; import lcsb.mapviewer.model.cache.UploadedFileEntry;
import lcsb.mapviewer.model.graphics.MapCanvasType; import lcsb.mapviewer.model.graphics.MapCanvasType;
import lcsb.mapviewer.model.map.*; import lcsb.mapviewer.model.map.*;
import lcsb.mapviewer.model.map.layout.ProjectBackground;
import lcsb.mapviewer.model.map.model.SubmodelType; import lcsb.mapviewer.model.map.model.SubmodelType;
import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Element;
import lcsb.mapviewer.model.security.PrivilegeType; import lcsb.mapviewer.model.security.PrivilegeType;
...@@ -755,4 +757,24 @@ public class ProjectRestImpl extends BaseRestImpl { ...@@ -755,4 +757,24 @@ public class ProjectRestImpl extends BaseRestImpl {
} }
} }
public List<ProjectBackground> getBackgrounds(String projectId) throws ObjectNotFoundException {
List<ProjectBackground> result = getProjectByProjectId(projectId).getProjectBackgrounds();
for (ProjectBackground projectBackground : result) {
Hibernate.initialize(projectBackground.getProjectBackgroundImageLayer());
}
return result;
}
public ProjectBackground getBackgroundById(String projectId, Integer backgroundId) {
throw new NotImplementedException();
}
public Map<String, Object> removeBackground(String projectId, Integer backgroundId) {
throw new NotImplementedException();
}
public ProjectBackground updateOverlay(String projectId, Integer overlayId, Map<String, Object> data) {
throw new NotImplementedException();
}
} }
...@@ -9,6 +9,8 @@ import org.springframework.web.servlet.ViewResolver; ...@@ -9,6 +9,8 @@ import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.*; import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver;
import com.fasterxml.jackson.databind.ObjectMapper;
import lcsb.mapviewer.api.SpringRestApiConfig; import lcsb.mapviewer.api.SpringRestApiConfig;
@Configuration @Configuration
...@@ -56,4 +58,10 @@ public class SpringWebConfig implements WebMvcConfigurer { ...@@ -56,4 +58,10 @@ public class SpringWebConfig implements WebMvcConfigurer {
.setViewName("index"); .setViewName("index");
} }
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
return mapper;
}
} }
...@@ -49,6 +49,7 @@ import lcsb.mapviewer.model.cache.UploadedFileEntry; ...@@ -49,6 +49,7 @@ import lcsb.mapviewer.model.cache.UploadedFileEntry;
import lcsb.mapviewer.model.graphics.*; import lcsb.mapviewer.model.graphics.*;
import lcsb.mapviewer.model.map.*; import lcsb.mapviewer.model.map.*;
import lcsb.mapviewer.model.map.kinetics.*; import lcsb.mapviewer.model.map.kinetics.*;
import lcsb.mapviewer.model.map.layout.*;
import lcsb.mapviewer.model.map.layout.graphics.Glyph; import lcsb.mapviewer.model.map.layout.graphics.Glyph;
import lcsb.mapviewer.model.map.model.*; import lcsb.mapviewer.model.map.model.*;
import lcsb.mapviewer.model.map.reaction.*; import lcsb.mapviewer.model.map.reaction.*;
...@@ -354,6 +355,20 @@ abstract public class ControllerIntegrationTest { ...@@ -354,6 +355,20 @@ abstract public class ControllerIntegrationTest {
project.addModel(map); project.addModel(map);
project.addModel(submap); project.addModel(submap);
ProjectBackground background = new ProjectBackground("Normal");
int id = 0;
for (ModelData model : project.getModels()) {
ProjectBackgroundImageLayer layer = new ProjectBackgroundImageLayer(model, "dir_" + (id++));
background.addProjectBackgroundImageLayer(layer);
}
background.setDefaultOverlay(true);
background.setOrderIndex(0);
background.setProgress(100);
background.setStatus(ProjectBackgroundStatus.OK);
background.setCreator(userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN));
project.addProjectBackground(background);
projectDao.add(project); projectDao.add(project);
return project; return project;
} }
......
...@@ -21,11 +21,14 @@ import org.junit.runner.RunWith; ...@@ -21,11 +21,14 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpSession; import org.springframework.mock.web.MockHttpSession;
import org.springframework.restdocs.request.ParameterDescriptor; import org.springframework.restdocs.payload.FieldDescriptor;
import org.springframework.restdocs.request.RequestParametersSnippet; import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.request.*;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.RequestBuilder; import org.springframework.test.web.servlet.RequestBuilder;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonParser; import com.google.gson.JsonParser;
import lcsb.mapviewer.api.projects.ProjectRestImpl; import lcsb.mapviewer.api.projects.ProjectRestImpl;
...@@ -33,6 +36,8 @@ import lcsb.mapviewer.model.Project; ...@@ -33,6 +36,8 @@ import lcsb.mapviewer.model.Project;
import lcsb.mapviewer.model.ProjectStatus; import lcsb.mapviewer.model.ProjectStatus;
import lcsb.mapviewer.model.cache.UploadedFileEntry; import lcsb.mapviewer.model.cache.UploadedFileEntry;
import lcsb.mapviewer.model.graphics.MapCanvasType; import lcsb.mapviewer.model.graphics.MapCanvasType;
import lcsb.mapviewer.model.map.layout.ProjectBackground;
import lcsb.mapviewer.model.map.layout.ProjectBackgroundStatus;
import lcsb.mapviewer.model.map.model.SubmodelType; import lcsb.mapviewer.model.map.model.SubmodelType;
import lcsb.mapviewer.model.security.Privilege; import lcsb.mapviewer.model.security.Privilege;
import lcsb.mapviewer.model.security.PrivilegeType; import lcsb.mapviewer.model.security.PrivilegeType;
...@@ -61,6 +66,9 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -61,6 +66,9 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
@Autowired @Autowired
private ProjectSnippets snippets; private ProjectSnippets snippets;
@Autowired
private ObjectMapper objectMapper;
private User curator; private User curator;
@Before @Before
...@@ -107,7 +115,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -107,7 +115,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
mockMvc.perform(request) mockMvc.perform(request)
.andExpect(status().is2xxSuccessful()) .andExpect(status().is2xxSuccessful())
.andDo(document("projects/project_data/get_source_file", .andDo(document("projects/project_data/get_source_file",
pathParameters(parameterWithName("projectId").description("project identifier")))); projectPathParameters()));
} }
...@@ -152,7 +160,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -152,7 +160,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
mockMvc.perform(request) mockMvc.perform(request)
.andDo(document("projects/project_data/get_project", .andDo(document("projects/project_data/get_project",
pathParameters(parameterWithName("projectId").description("project identifier")), projectPathParameters(),
snippets.getProjectSnippet())) snippets.getProjectSnippet()))
.andExpect(status().is2xxSuccessful()); .andExpect(status().is2xxSuccessful());
} }
...@@ -179,7 +187,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -179,7 +187,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
parameterWithName("level").description("level of log entry (warning, error)").optional(), parameterWithName("level").description("level of log entry (warning, error)").optional(),
parameterWithName("length").description("number of log entres we want to obtain").optional(), parameterWithName("length").description("number of log entres we want to obtain").optional(),
parameterWithName("search").description("search query used for filtering").optional()), parameterWithName("search").description("search query used for filtering").optional()),
pathParameters(parameterWithName("projectId").description("project identifier")), projectPathParameters(),
responseFields( responseFields(
subsectionWithPath("data") subsectionWithPath("data")
.description("list of log entries") .description("list of log entries")
...@@ -207,7 +215,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -207,7 +215,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
RequestBuilder request = get("/projects/{projectId}/statistics", TEST_PROJECT).session(session); RequestBuilder request = get("/projects/{projectId}/statistics", TEST_PROJECT).session(session);
mockMvc.perform(request).andDo(document("projects/project_data/get_project_statistics", mockMvc.perform(request).andDo(document("projects/project_data/get_project_statistics",
pathParameters(parameterWithName("projectId").description("project identifier")), projectPathParameters(),
responseFields( responseFields(
subsectionWithPath("reactionAnnotations") subsectionWithPath("reactionAnnotations")
.description("list of reaction annotation types") .description("list of reaction annotation types")
...@@ -238,7 +246,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -238,7 +246,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
mockMvc.perform(request) mockMvc.perform(request)
.andDo(document("projects/project_privileges/grant_privilege", .andDo(document("projects/project_privileges/grant_privilege",
pathParameters(parameterWithName("projectId").description("project identifier")), projectPathParameters(),
requestFields( requestFields(
fieldWithPath("[]") fieldWithPath("[]")
.description("list of privileges to grant") .description("list of privileges to grant")
...@@ -276,7 +284,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -276,7 +284,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
mockMvc.perform(request) mockMvc.perform(request)
.andDo(document("projects/project_privileges/revoke_privilege", .andDo(document("projects/project_privileges/revoke_privilege",
pathParameters(parameterWithName("projectId").description("project identifier")), projectPathParameters(),
requestFields( requestFields(
fieldWithPath("[]") fieldWithPath("[]")
.description("list of privileges to revoke") .description("list of privileges to revoke")
...@@ -324,7 +332,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -324,7 +332,7 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
mockMvc.perform(request) mockMvc.perform(request)
.a