diff --git a/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoViewService.java b/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoViewService.java index f8298f896..c878ee5cb 100644 --- a/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoViewService.java +++ b/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoViewService.java @@ -52,6 +52,9 @@ public void addChildViews(ElementsResponse res, Map params) { for (ElementJson element: res.getElements()) { if (cameoHelper.isView(element)) { List ownedAttributeIds = (List) element.get(CameoConstants.OWNEDATTRIBUTEIDS); + if (ownedAttributeIds == null) { + ownedAttributeIds = new ArrayList<>(); + } ElementsResponse ownedAttributes = this.read(element.getProjectId(), element.getRefId(), buildRequest(ownedAttributeIds), params); List sorted = nodeGetHelper.sort(ownedAttributeIds, ownedAttributes.getElements()); diff --git a/core/src/main/java/org/openmbee/mms/core/objects/ElementsRequest.java b/core/src/main/java/org/openmbee/mms/core/objects/ElementsRequest.java index 9b26dd8fa..d19174c19 100644 --- a/core/src/main/java/org/openmbee/mms/core/objects/ElementsRequest.java +++ b/core/src/main/java/org/openmbee/mms/core/objects/ElementsRequest.java @@ -12,6 +12,8 @@ public class ElementsRequest extends BaseRequest { private List deletes; + private String lastCommitId; + public List getElements() { return elements; } @@ -27,4 +29,12 @@ public List getDeletes() { public void setDeletes(List deletes) { this.deletes = deletes; } + + public String getLastCommitId() { + return lastCommitId; + } + + public void setLastCommitId(String lastCommitId) { + this.lastCommitId = lastCommitId; + } } diff --git a/core/src/main/java/org/openmbee/mms/core/objects/ElementsResponse.java b/core/src/main/java/org/openmbee/mms/core/objects/ElementsResponse.java index 60fc16710..b5c984863 100644 --- a/core/src/main/java/org/openmbee/mms/core/objects/ElementsResponse.java +++ b/core/src/main/java/org/openmbee/mms/core/objects/ElementsResponse.java @@ -8,7 +8,7 @@ public class ElementsResponse extends BaseResponse { private List elements; - + private String commitId; public ElementsResponse() { this.elements = new ArrayList<>(); } @@ -21,4 +21,11 @@ public ElementsResponse setElements(List elements) { this.elements = elements; return this; } + public String getCommitId() { + return commitId; + } + + public void setCommitId(String commitId) { + this.commitId = commitId; + } } diff --git a/core/src/main/java/org/openmbee/mms/core/services/NodeGetInfo.java b/core/src/main/java/org/openmbee/mms/core/services/NodeGetInfo.java index dd417d49f..a718e7c81 100644 --- a/core/src/main/java/org/openmbee/mms/core/services/NodeGetInfo.java +++ b/core/src/main/java/org/openmbee/mms/core/services/NodeGetInfo.java @@ -23,6 +23,8 @@ public class NodeGetInfo { Map rejected; + String commitId; + public Set getReqIndexIds() { return reqIndexIds; @@ -87,4 +89,12 @@ public void addRejection(String id, Rejection rejection) { this.rejected.put(id, rejection); } + public void setCommitId(String commitId) { + this.commitId = commitId; + } + + public String getCommitId() { + return this.commitId; + } + } diff --git a/crud/src/main/java/org/openmbee/mms/crud/services/DefaultNodeService.java b/crud/src/main/java/org/openmbee/mms/crud/services/DefaultNodeService.java index 564cc6f71..6beb8ae60 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/services/DefaultNodeService.java +++ b/crud/src/main/java/org/openmbee/mms/crud/services/DefaultNodeService.java @@ -105,17 +105,21 @@ public void readAsStream(String projectId, String refId, String commitId = params.getOrDefault("commitId", null); ContextHolder.setContext(projectId, refId); List nodes; + String resCommitId; if (commitId != null && !commitId.isEmpty()) { if (!commitRepository.findByCommitId(commitId).isPresent()) { throw new BadRequestException("commit id is invalid"); } nodes = nodeRepository.findAll(); + resCommitId = commitId; } else { nodes = nodeRepository.findAllByDeleted(false); + resCommitId = nodeGetHelper.getLatestRefCommitId(); } String separator = "\n"; if (!"application/x-ndjson".equals(accept)) { - stream.write("{\"elements\":[".getBytes(StandardCharsets.UTF_8)); + String intro = "{\"commitId\":" + (resCommitId == null ? "null" : "\"" + resCommitId + "\"") + ",\"elements\":["; + stream.write(intro.getBytes(StandardCharsets.UTF_8)); separator = ","; } final String sep = separator; @@ -162,6 +166,11 @@ public ElementsResponse read(String projectId, String refId, String id, ElementsResponse response = new ElementsResponse(); String commitId = params.getOrDefault("commitId", null); response.getElements().addAll(nodeGetHelper.processGetAll(commitId, this)); + if (commitId != null) { + response.setCommitId(commitId); + } else { + response.setCommitId(nodeGetHelper.getLatestRefCommitId()); + } return response; } } @@ -178,6 +187,7 @@ public ElementsResponse read(String projectId, String refId, ElementsRequest req ElementsResponse response = new ElementsResponse(); response.getElements().addAll(info.getActiveElementMap().values()); response.setRejected(new ArrayList<>(info.getRejected().values())); + response.setCommitId(info.getCommitId()); return response; } @@ -189,10 +199,11 @@ public ElementsCommitResponse createOrUpdate(String projectId, String refId, Ele boolean overwriteJson = Boolean.parseBoolean(params.get("overwrite")); nodePostHelper.setPreserveTimestamps(Boolean.parseBoolean(params.get("preserveTimestamps"))); String commitId = params.get("commitId"); + String lastCommitId = req.getLastCommitId(); NodeChangeInfo info = nodePostHelper .processPostJson(req.getElements(), overwriteJson, - createCommit(user, refId, projectId, req, commitId), this); + createCommit(user, refId, projectId, req, commitId), this, lastCommitId); if (req.getDeletes() != null && !req.getDeletes().isEmpty()) { NodeChangeInfo delete = nodeDeleteHelper.processDeleteJson(req.getDeletes(), createCommit(user, refId, projectId, req, info.getCommitJson().getCommitId()), this); diff --git a/crud/src/main/java/org/openmbee/mms/crud/services/NodeGetHelper.java b/crud/src/main/java/org/openmbee/mms/crud/services/NodeGetHelper.java index bd410b082..61faa7226 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/services/NodeGetHelper.java +++ b/crud/src/main/java/org/openmbee/mms/crud/services/NodeGetHelper.java @@ -52,6 +52,7 @@ private NodeGetInfo processLatest(NodeGetInfo info, NodeService service) { } info.getActiveElementMap().put(nodeId, indexElement); } + info.setCommitId(getLatestRefCommitId()); return info; } @@ -76,6 +77,7 @@ private NodeGetInfo processCommit(NodeGetInfo info, String commitId, NodeService if (!commit.isPresent() ) { throw new BadRequestException("commitId is invalid"); } + info.setCommitId(commitId); Instant time = commit.get().getTimestamp(); //time of commit List refCommitIds = null; //get it later if needed for (String nodeId : info.getReqElementMap().keySet()) { diff --git a/crud/src/main/java/org/openmbee/mms/crud/services/NodeOperation.java b/crud/src/main/java/org/openmbee/mms/crud/services/NodeOperation.java index 0a0d69b59..d6d465a4e 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/services/NodeOperation.java +++ b/crud/src/main/java/org/openmbee/mms/crud/services/NodeOperation.java @@ -18,6 +18,8 @@ import org.openmbee.mms.core.services.NodeGetInfo; import org.openmbee.mms.core.dao.BranchDAO; import org.openmbee.mms.core.dao.CommitDAO; +import org.openmbee.mms.data.domains.scoped.Branch; +import org.openmbee.mms.data.domains.scoped.Commit; import org.openmbee.mms.data.domains.scoped.Node; import org.openmbee.mms.core.dao.NodeDAO; import org.openmbee.mms.core.dao.NodeIndexDAO; @@ -274,4 +276,14 @@ public boolean isPreserveTimestamps() { public void setPreserveTimestamps(boolean preserveTimestamps) { this.preserveTimestamps = preserveTimestamps; } + + public String getLatestRefCommitId() { + Optional branch = branchRepository.findByBranchId(ContextHolder.getContext().getBranchId()); + Optional commit = commitRepository.findLatestByRef(branch.get()); + if (commit.isPresent()) { + return commit.get().getCommitId(); + } else { + return null; + } + } } diff --git a/crud/src/main/java/org/openmbee/mms/crud/services/NodePostHelper.java b/crud/src/main/java/org/openmbee/mms/crud/services/NodePostHelper.java index 34f9a3112..e0b9d27a5 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/services/NodePostHelper.java +++ b/crud/src/main/java/org/openmbee/mms/crud/services/NodePostHelper.java @@ -8,6 +8,7 @@ import java.util.Optional; import java.util.UUID; import org.openmbee.mms.core.config.Formats; +import org.openmbee.mms.core.exceptions.ConflictException; import org.openmbee.mms.core.objects.Rejection; import org.openmbee.mms.core.services.NodeChangeInfo; import org.openmbee.mms.core.services.NodeService; @@ -54,8 +55,12 @@ public boolean diffUpdateJson(BaseJson element, Map existing, // create new elastic id for all element json, update modified time, modifier (use dummy for now), set _projectId, _refId, _inRefIds public NodeChangeInfo processPostJson(List elements, boolean overwriteJson, - CommitJson cmjs, NodeService service) { - + CommitJson cmjs, NodeService service, String lastCommitId) { + if (lastCommitId != null && !lastCommitId.isEmpty()) { + if (!lastCommitId.equals(getLatestRefCommitId())) { + throw new ConflictException("Given commitId " + lastCommitId + " is not the latest"); + } + } NodeChangeInfo info = initInfo(elements, cmjs); // Logic for update/add diff --git a/example/crud.postman_collection.json b/example/crud.postman_collection.json index 6cd1f98f8..2bcb351bc 100644 --- a/example/crud.postman_collection.json +++ b/example/crud.postman_collection.json @@ -412,6 +412,95 @@ }, "response": [] }, + { + "name": "get all elements returns last commitId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has 3 elements and correct commitId\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(3);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get(\"commitId1\"))", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{host}}/projects/aa/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "aa", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "post elements with wrong lastCommitId results in 409", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response code is 409\", function () {", + " pm.response.to.have.status(409);", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{ \"lastCommitId\": \"blah\",\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"x\",\n\t\t\t\"name\": \"x\"\n\t\t}, {\n\t\t\t\"id\": \"y\", \n\t\t\t\"name\": \"y\"\n\t\t}, {\n\t\t\t\"id\": \"z\",\n\t\t\t\"name\": \"z\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/aa/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "aa", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, { "name": "update x", "event": [