Commit fab2320f authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch '1085-allow-to-fetch-modifier-type-by-api' into 'master'

Resolve "allow to fetch modifier type by API"

See merge request !1329
parents 2c649f66 ba100974
Pipeline #45978 failed with stage
in 36 minutes and 33 seconds
minerva (16.1.0~alpha.0) stable; urgency=medium minerva (16.1.0~alpha.0) stable; urgency=medium
* Small improvement: API provides information about modifier type (#1085)
* Bug fix: api endpoints were exposed without 'api' prefix * Bug fix: api endpoints were exposed without 'api' prefix
* Bug fix: anonymous user could upload file using API * Bug fix: anonymous user could upload file using API
* Bug fix: when passing JSON in patch/post methods contentType was not * Bug fix: when passing JSON in patch/post methods contentType was not
......
package lcsb.mapviewer.model.map.reaction; package lcsb.mapviewer.model.map.reaction;
import javax.persistence.*; import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Element;
import lcsb.mapviewer.modelutils.map.ElementUtils; import lcsb.mapviewer.modelutils.map.ElementUtils;
import lcsb.mapviewer.modelutils.serializer.model.map.reaction.ReactionNodeSerializer;
/** /**
* One of two known types of nodes in the {@link Reaction}. It defines input or * One of two known types of nodes in the {@link Reaction}. It defines input or
...@@ -22,6 +27,7 @@ import lcsb.mapviewer.modelutils.map.ElementUtils; ...@@ -22,6 +27,7 @@ import lcsb.mapviewer.modelutils.map.ElementUtils;
*/ */
@Entity @Entity
@DiscriminatorValue("GENERIC_REACTION_NODE") @DiscriminatorValue("GENERIC_REACTION_NODE")
@JsonSerialize(using = ReactionNodeSerializer.class)
public abstract class ReactionNode extends AbstractNode { public abstract class ReactionNode extends AbstractNode {
/** /**
......
...@@ -15,16 +15,9 @@ import javax.persistence.UniqueConstraint; ...@@ -15,16 +15,9 @@ import javax.persistence.UniqueConstraint;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import lcsb.mapviewer.modelutils.serializer.model.security.PrivilegeDeserializer;
import lcsb.mapviewer.modelutils.serializer.model.security.PrivilegeSerializer;
@Entity @Entity
@Table(uniqueConstraints = @UniqueConstraint(columnNames = { "type", "objectId" })) @Table(uniqueConstraints = @UniqueConstraint(columnNames = { "type", "objectId" }))
@JsonSerialize(using = PrivilegeSerializer.class)
@JsonDeserialize(using = PrivilegeDeserializer.class)
public class Privilege implements Serializable { public class Privilege implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
......
package lcsb.mapviewer.modelutils.serializer.model.security; package lcsb.mapviewer.modelutils.serializer.model.map.reaction;
import java.io.IOException; import java.io.IOException;
...@@ -6,19 +6,19 @@ import com.fasterxml.jackson.core.JsonGenerator; ...@@ -6,19 +6,19 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.SerializerProvider;
import lcsb.mapviewer.model.security.Privilege; import lcsb.mapviewer.model.map.reaction.ReactionNode;
public class PrivilegeSerializer extends JsonSerializer<Privilege> { public class ReactionNodeSerializer extends JsonSerializer<ReactionNode> {
@Override @Override
public void serialize(final Privilege entry, final JsonGenerator gen, public void serialize(final ReactionNode node, final JsonGenerator gen,
final SerializerProvider serializers) final SerializerProvider serializers)
throws IOException { throws IOException {
if (entry.isObjectPrivilege()) { gen.writeStartObject();
gen.writeString(entry.getType()+":"+entry.getObjectId()); gen.writeNumberField("aliasId", node.getElement().getId());
} else { gen.writeObjectField("stoichiometry", node.getStoichiometry());
gen.writeStringField("type", node.getClass().getSimpleName());
gen.writeString(entry.getType().name()); gen.writeEndObject();
}
} }
} }
\ No newline at end of file
package lcsb.mapviewer.modelutils.serializer.model.security;
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lcsb.mapviewer.model.security.Privilege;
public class PrivilegeDeserializer extends StdDeserializer<Privilege> {
/**
*
*/
private static final long serialVersionUID = 1L;
public PrivilegeDeserializer() {
super(Privilege.class);
}
@Override
public Privilege deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) parser.getCodec();
ObjectNode rootNode = mapper.readTree(parser);
return new PrivilegeKeyDeserializer().deserializeKey(rootNode.asText(), ctxt);
}
}
...@@ -284,6 +284,9 @@ public class ProjectController extends BaseController { ...@@ -284,6 +284,9 @@ public class ProjectController extends BaseController {
@RequestParam Map<String, Object> body, @RequestParam Map<String, Object> body,
@PathVariable(value = "projectId") String projectId) throws IOException, QueryException, SecurityException { @PathVariable(value = "projectId") String projectId) throws IOException, QueryException, SecurityException {
fixFormUrlEncodedBody(body); fixFormUrlEncodedBody(body);
if (Objects.equals(body.get("zip-entries"), "")) {
body.remove("zip-entries");
}
CreateProjectDTO data = objectMapper.readValue(objectMapper.writeValueAsString(body), CreateProjectDTO.class); CreateProjectDTO data = objectMapper.readValue(objectMapper.writeValueAsString(body), CreateProjectDTO.class);
if (projectId.equals("*")) { if (projectId.equals("*")) {
......
...@@ -36,7 +36,6 @@ import lcsb.mapviewer.model.map.reaction.NodeOperator; ...@@ -36,7 +36,6 @@ import lcsb.mapviewer.model.map.reaction.NodeOperator;
import lcsb.mapviewer.model.map.reaction.Product; import lcsb.mapviewer.model.map.reaction.Product;
import lcsb.mapviewer.model.map.reaction.Reactant; import lcsb.mapviewer.model.map.reaction.Reactant;
import lcsb.mapviewer.model.map.reaction.Reaction; import lcsb.mapviewer.model.map.reaction.Reaction;
import lcsb.mapviewer.model.map.reaction.ReactionNode;
import lcsb.mapviewer.modelutils.serializer.MathMLSerializer; import lcsb.mapviewer.modelutils.serializer.MathMLSerializer;
import lcsb.mapviewer.services.QueryException; import lcsb.mapviewer.services.QueryException;
import lcsb.mapviewer.services.interfaces.IReactionService; import lcsb.mapviewer.services.interfaces.IReactionService;
...@@ -113,27 +112,15 @@ public class ReactionsController extends BaseController { ...@@ -113,27 +112,15 @@ public class ReactionsController extends BaseController {
value = pt.getPointOnLine(centerLine.getP1(), centerLine.getP2(), 0.5); value = pt.getPointOnLine(centerLine.getP1(), centerLine.getP2(), 0.5);
break; break;
case "products": { case "products": {
List<Map<String, Object>> ids = new ArrayList<>(); value = reaction.getProducts();
for (Product product : reaction.getProducts()) {
ids.add(createReactionNode(product));
}
value = ids;
break; break;
} }
case "reactants": { case "reactants": {
List<Map<String, Object>> ids = new ArrayList<>(); value = reaction.getReactants();
for (Reactant reactant : reaction.getReactants()) {
ids.add(createReactionNode(reactant));
}
value = ids;
break; break;
} }
case "modifiers": { case "modifiers": {
List<Map<String, Object>> ids = new ArrayList<>(); value = reaction.getModifiers();
for (Modifier modifier : reaction.getModifiers()) {
ids.add(createReactionNode(modifier));
}
value = ids;
break; break;
} }
case "type": case "type":
...@@ -233,13 +220,6 @@ public class ReactionsController extends BaseController { ...@@ -233,13 +220,6 @@ public class ReactionsController extends BaseController {
return result; return result;
} }
private Map<String, Object> createReactionNode(ReactionNode node) {
Map<String, Object> result = new TreeMap<>();
result.put("aliasId", node.getElement().getId());
result.put("stoichiometry", node.getStoichiometry());
return result;
}
private Map<String, Object> kineticsToMap(SbmlKinetics kinetics) { private Map<String, Object> kineticsToMap(SbmlKinetics kinetics) {
if (kinetics == null) { if (kinetics == null) {
return null; return null;
......
...@@ -109,6 +109,9 @@ public class UserController extends BaseController { ...@@ -109,6 +109,9 @@ public class UserController extends BaseController {
if (user == null) { if (user == null) {
throw new ObjectNotFoundException("User doesn't exist"); throw new ObjectNotFoundException("User doesn't exist");
} }
if (user.getAnnotationSchema() == null) {
user.setAnnotationSchema(projectService.prepareUserAnnotationSchema(user, true));
}
Boolean ldapAvailable = false; Boolean ldapAvailable = false;
if (columnSet.contains("ldapAccountAvailable")) { if (columnSet.contains("ldapAccountAvailable")) {
List<User> userList = new ArrayList<>(); List<User> userList = new ArrayList<>();
......
...@@ -1382,4 +1382,9 @@ public class ProjectService implements IProjectService { ...@@ -1382,4 +1382,9 @@ public class ProjectService implements IProjectService {
return new ArrayList<>(); return new ArrayList<>();
} }
} }
@Override
public void add(Project project) {
projectDao.add(project);
}
} }
...@@ -124,4 +124,6 @@ public interface IProjectService { ...@@ -124,4 +124,6 @@ public interface IProjectService {
UploadedFileEntry getFileByProjectId(String projectId); UploadedFileEntry getFileByProjectId(String projectId);
List<ProjectBackground> getBackgrounds(String projectId, boolean initializeLazy); List<ProjectBackground> getBackgrounds(String projectId, boolean initializeLazy);
void add(Project project);
} }
...@@ -22,7 +22,6 @@ import org.junit.runners.Suite.SuiteClasses; ...@@ -22,7 +22,6 @@ import org.junit.runners.Suite.SuiteClasses;
ParameterControllerIntegrationTest.class, ParameterControllerIntegrationTest.class,
PluginControllerIntegrationTest.class, PluginControllerIntegrationTest.class,
ProjectControllerIntegrationTest.class, ProjectControllerIntegrationTest.class,
ProjectControllerIntegrationTestForAsyncCalls.class,
PublicationsControllerIntegrationTest.class, PublicationsControllerIntegrationTest.class,
ReactionControllerIntegrationTest.class, ReactionControllerIntegrationTest.class,
SpringSecurityGeneralIntegrationTest.class, SpringSecurityGeneralIntegrationTest.class,
......
...@@ -107,6 +107,7 @@ import lcsb.mapviewer.persist.dao.map.ModelDao; ...@@ -107,6 +107,7 @@ import lcsb.mapviewer.persist.dao.map.ModelDao;
import lcsb.mapviewer.persist.dao.user.ResetPasswordTokenDao; import lcsb.mapviewer.persist.dao.user.ResetPasswordTokenDao;
import lcsb.mapviewer.persist.dao.user.UserDao; import lcsb.mapviewer.persist.dao.user.UserDao;
import lcsb.mapviewer.services.interfaces.IDataOverlayService; import lcsb.mapviewer.services.interfaces.IDataOverlayService;
import lcsb.mapviewer.services.interfaces.IFileService;
import lcsb.mapviewer.services.interfaces.IProjectService; import lcsb.mapviewer.services.interfaces.IProjectService;
import lcsb.mapviewer.services.interfaces.IUserService; import lcsb.mapviewer.services.interfaces.IUserService;
import lcsb.mapviewer.web.config.SpringWebConfig; import lcsb.mapviewer.web.config.SpringWebConfig;
...@@ -161,6 +162,9 @@ abstract public class ControllerIntegrationTest { ...@@ -161,6 +162,9 @@ abstract public class ControllerIntegrationTest {
@Autowired @Autowired
private UploadedFileEntryDao fileDao; private UploadedFileEntryDao fileDao;
@Autowired
private IFileService fileService;
@Autowired @Autowired
private DataOverlayDao dataOverlayDao; private DataOverlayDao dataOverlayDao;
...@@ -444,7 +448,7 @@ abstract public class ControllerIntegrationTest { ...@@ -444,7 +448,7 @@ abstract public class ControllerIntegrationTest {
background.setCreator(userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN)); background.setCreator(userService.getUserByLogin(BUILT_IN_TEST_ADMIN_LOGIN));
project.addProjectBackground(background); project.addProjectBackground(background);
projectDao.add(project); projectService.add(project);
return project; return project;
} }
...@@ -516,7 +520,7 @@ abstract public class ControllerIntegrationTest { ...@@ -516,7 +520,7 @@ abstract public class ControllerIntegrationTest {
file.setOriginalFileName("test_file"); file.setOriginalFileName("test_file");
file.setLength(content.length); file.setLength(content.length);
file.setOwner(user); file.setOwner(user);
fileDao.add(file); fileService.add(file);
return file; return file;
} }
......
...@@ -16,6 +16,8 @@ import static org.springframework.restdocs.request.RequestDocumentation.pathPara ...@@ -16,6 +16,8 @@ import static org.springframework.restdocs.request.RequestDocumentation.pathPara
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters; import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
...@@ -30,6 +32,8 @@ import org.junit.runner.RunWith; ...@@ -30,6 +32,8 @@ 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.payload.FieldDescriptor;
import org.springframework.restdocs.payload.JsonFieldType;
import org.springframework.restdocs.payload.ResponseFieldsSnippet; import org.springframework.restdocs.payload.ResponseFieldsSnippet;
import org.springframework.restdocs.request.PathParametersSnippet; import org.springframework.restdocs.request.PathParametersSnippet;
import org.springframework.restdocs.request.RequestParametersSnippet; import org.springframework.restdocs.request.RequestParametersSnippet;
...@@ -229,62 +233,85 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest { ...@@ -229,62 +233,85 @@ public class MapControllerIntegrationTest extends ControllerIntegrationTest {
} }
private ResponseFieldsSnippet listOfReactionResponseFields() { private ResponseFieldsSnippet listOfReactionResponseFields() {
return responseFields( List<FieldDescriptor> fields = new ArrayList<>(Arrays.asList(
fieldWithPath("[].id") fieldWithPath("[].id")
.description("unique element identifier") .description("unique element identifier")
.type("number") .type(JsonFieldType.NUMBER)
.optional(), .optional(),
fieldWithPath("[].reactionId") fieldWithPath("[].reactionId")
.description("reaction identifier taken from source file") .description("reaction identifier taken from source file")
.type("string") .type(JsonFieldType.STRING)
.optional(), .optional(),
fieldWithPath("[].modelId") fieldWithPath("[].modelId")
.description("map identifier") .description("map identifier")
.type("number") .type(JsonFieldType.NUMBER)
.optional(), .optional(),
fieldWithPath("[].type") fieldWithPath("[].type")
.description("reaction type") .description("reaction type")
.type("string") .type(JsonFieldType.STRING)
.optional(), .optional(),
subsectionWithPath("[].centerPoint") subsectionWithPath("[].centerPoint")
.description("center point") .description("center point")
.type("point") .type(JsonFieldType.OBJECT)
.optional(), .optional(),
subsectionWithPath("[].lines") subsectionWithPath("[].lines")
.description("list of lines used to draw reaction") .description("list of lines used to draw reaction")
.type("array<line>") .type(JsonFieldType.ARRAY)
.optional(), .optional(),
fieldWithPath("[].hierarchyVisibilityLevel") fieldWithPath("[].hierarchyVisibilityLevel")
.description("at what zoom level this element becomes visible in hierarchical view") .description("at what zoom level this element becomes visible in hierarchical view")
.type("string") .type(JsonFieldType.STRING)
.optional(), .optional(),
subsectionWithPath("[].references") subsectionWithPath("[].references")
.description("list of references") .description("list of references")
.type("array<Reference>") .type(JsonFieldType.ARRAY)
.optional(), .optional(),
subsectionWithPath("[].modifiers") fieldWithPath("[].modifiers")
.description("list of modifiers") .description("list of modifiers")
.type("array<object>") .type(JsonFieldType.ARRAY)
.optional(), .optional(),
subsectionWithPath("[].reactants") fieldWithPath("[].reactants")
.description("list of reactants") .description("list of reactants")
.type("array<object>") .type(JsonFieldType.ARRAY)
.optional(), .optional(),
subsectionWithPath("[].products") fieldWithPath("[].products")
.description("list of products") .description("list of products")
.type("array<object>") .type(JsonFieldType.ARRAY)
.optional(), .optional(),
fieldWithPath("[].notes") fieldWithPath("[].notes")
.description("notes and description") .description("notes and description")
.type("string") .type(JsonFieldType.STRING)
.optional(), .optional(),
fieldWithPath("[].kineticLaw") fieldWithPath("[].kineticLaw")
.description("SBML kinetics law") .description("SBML kinetics law")
.type("object") .type(JsonFieldType.OBJECT)
.optional(), .optional(),
subsectionWithPath("[].other") subsectionWithPath("[].other")
.description("list of oher properties") .description("list of oher properties")
.type("object") .type(JsonFieldType.OBJECT)
.optional()));
fields.addAll(reactionNodeFields("[].reactants[]"));
fields.addAll(reactionNodeFields("[].products[]"));
fields.addAll(reactionNodeFields("[].modifiers[]"));
return responseFields(fields);
}
private List<FieldDescriptor> reactionNodeFields(String prefix) {
if (!prefix.endsWith(".") && !prefix.isEmpty()) {
prefix = prefix + ".";
}
return Arrays.asList(
fieldWithPath(prefix + "aliasId")
.description("element identifier")
.type(JsonFieldType.NUMBER)
.optional(),
fieldWithPath(prefix + "type")
.description("type")
.type(JsonFieldType.STRING)
.optional(),
fieldWithPath(prefix + "stoichiometry")
.description("element stoichiometry")
.type(JsonFieldType.STRING)
.optional()); .optional());
} }
......
...@@ -2,6 +2,7 @@ package lcsb.mapviewer.web; ...@@ -2,6 +2,7 @@ package lcsb.mapviewer.web;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.delete;
...@@ -58,7 +59,6 @@ import lcsb.mapviewer.model.map.model.SubmodelType; ...@@ -58,7 +59,6 @@ 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;
import lcsb.mapviewer.model.user.User; import lcsb.mapviewer.model.user.User;
import lcsb.mapviewer.persist.dao.ProjectDao;
import lcsb.mapviewer.services.interfaces.IProjectService; import lcsb.mapviewer.services.interfaces.IProjectService;
import lcsb.mapviewer.services.interfaces.IUserService; import lcsb.mapviewer.services.interfaces.IUserService;
import lcsb.mapviewer.web.serialization.ProjectBackgroundUpdateMixIn; import lcsb.mapviewer.web.serialization.ProjectBackgroundUpdateMixIn;
...@@ -66,8 +66,11 @@ import lcsb.mapviewer.web.serialization.ProjectBackgroundUpdateMixIn; ...@@ -66,8 +66,11 @@ import lcsb.mapviewer.web.serialization.ProjectBackgroundUpdateMixIn;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
public class ProjectControllerIntegrationTest extends ControllerIntegrationTest { public class ProjectControllerIntegrationTest extends ControllerIntegrationTest {
private static final String CURATOR_PASSWORD = "test_pass"; private static final String CURATOR_PASSWORD = "curator_pass";
private static final String CURATOR_LOGIN = "test_user"; private static final String CURATOR_LOGIN = "curator_user";
private static final String USER_PASSWORD = "user_pass";
private static final String USER_LOGIN = "test_user";
private static final String TEST_PROJECT_2 = "test_project2"; private static final String TEST_PROJECT_2 = "test_project2";
Logger logger = LogManager.getLogger(); Logger logger = LogManager.getLogger();
...@@ -77,9 +80,6 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest ...@@ -77,9 +80,6 @@ public class ProjectControllerIntegrationTest extends ControllerIntegrationTest
@Autowired @Autowired
private IProjectService projectService; private IProjectService projectService;
@Autowired
private ProjectDao projectDao;
@Autowired @Autowired
private ProjectSnippets snippets; private ProjectSnippets snippets;