diff --git a/.circleci/config.yml b/.circleci/config.yml index a55ff8509..2df37eca6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,27 +20,36 @@ jobs: - setup_remote_docker - - run: + - run: name: "Create and start all services from the docker-compose configuration" command: | cp example/src/main/resources/application.properties.example ./example/src/main/resources/application.properties + mkdir -p jacocoJars + curl -L -o ./jacocoJars/jacocoagent.jar "https://repo1.maven.org/maven2/org/jacoco/org.jacoco.agent/0.8.7/org.jacoco.agent-0.8.7-runtime.jar" + curl -L -o ./jacocoJars/jacococli.jar "https://repo1.maven.org/maven2/org/jacoco/org.jacoco.cli/0.8.7/org.jacoco.cli-0.8.7-nodeps.jar" docker-compose up --build -d docker run --network container:mms curlimages/curl --retry 8 --retry-delay 10 --retry-max-time 90 --retry-connrefused http://mms:8080/healthcheck - - run: + - run: name: "Run and test Postman Collection" command: | docker create -v /etc/newman --name mms_test_configs alpine:3.4 /bin/true docker cp example/. mms_test_configs:/etc/newman - docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run crud.postman_collection.json -e test-env.json --delay-request 1000 - docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run cameo.postman_collection.json -e test-env.json --delay-request 1000 + docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run crud.postman_collection.json -e test-env.json --delay-request 500 + docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run getAtCommits.postman_collection.json -e test-env.json --delay-request 500 + docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run makeBranchFromCommit.postman_collection.json -e test-env.json --delay-request 500 + docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run cameo.postman_collection.json -e test-env.json --delay-request 500 docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run jupyter.postman_collection.json -e test-env.json --delay-request 500 docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run localauth.postman_collection.json -e test-env.json --delay-request 500 - docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run permissions.postman_collection.json -e test-env.json --delay-request 1000 + docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run permissions.postman_collection.json -e test-env.json --delay-request 500 docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run search.postman_collection.json -e test-env.json --delay-request 1000 - docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run artifacts.postman_collection.json -e test-env.json --delay-request 1000 + docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run artifacts.postman_collection.json -e test-env.json --delay-request 500 docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run elastic.postman_collection.json -e test-env.json --delay-request 500 docker run --volumes-from mms_test_configs --network container:mms -t postman/newman run groups.postman_collection.json -e test-env.json --delay-request 500 + + docker stop mms + mkdir -p jacocoOutput + docker cp mms:/mms/jacocoOutput/jacoco-it.exec ./jacocoOutput/jacoco-it.exec - persist_to_workspace: root: /home/circleci/ @@ -51,10 +60,17 @@ jobs: executor: openjdk_executor working_directory: /home/circleci/mms steps: - - checkout + - attach_workspace: + at: ~/ - run: name: Build classes to scan - command: ./gradlew build -x test + command: | + ./gradlew build -x test + mkdir -p TEMPORARYclassfiles + cp -r */build/classes/java/main/* TEMPORARYclassfiles/ + java -jar jacocoJars/jacococli.jar report jacocoOutput/jacoco-it.exec --classfiles TEMPORARYclassfiles/ --xml ./jacocoOutput/jacocoXMLReport + rm -r TEMPORARYclassfiles + - sonarcloud/scan deploy_snapshot: @@ -85,6 +101,8 @@ workflows: tags: only: /[0-9.]+(-(a|b|rc)[0-9]+)?/ - scan: + requires: + - build_and_test filters: tags: only: /[0-9.]+(-(a|b|rc)[0-9]+)?/ diff --git a/.readthedocs.yaml b/.readthedocs.yaml index a0c403c64..57f555c9e 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -17,6 +17,6 @@ sphinx: # We recommend specifying your dependencies to enable reproducible builds: # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html -# python: -# install: -# - requirements: docs/requirements.txt \ No newline at end of file +python: + install: + - requirements: docs/requirements.txt \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index e027f83cd..d7fdacdfa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,5 +5,5 @@ RUN ./gradlew --no-daemon bootJar --warning-mode all RUN find . -type f -name example-*.jar -not -iname '*javadoc*' -not -iname '*sources*' -exec cp '{}' '/app.jar' ';' ENV JDK_JAVA_OPTIONS "-XX:MaxRAMPercentage=90.0" -ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-jar", "/app.jar"] +ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "-javaagent:jacocoJars/jacocoagent.jar=destfile=jacocoOutput/jacoco-it.exec,output=file", "-jar", "/app.jar"] EXPOSE 8080 diff --git a/build.gradle b/build.gradle index 529b26a1e..daf69f28b 100644 --- a/build.gradle +++ b/build.gradle @@ -65,6 +65,7 @@ subprojects { group = "org.openmbee.mms" version = rootProject.version + ext['jackson-bom.version'] = jacksonVersion Map commonDependencies = rootProject.ext.commonDependencies @@ -160,4 +161,4 @@ subprojects { sign publishing.publications.mavenJava } } -} +} \ No newline at end of file diff --git a/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoCommitService.java b/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoCommitService.java index 35c326ecc..a5999f50e 100644 --- a/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoCommitService.java +++ b/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoCommitService.java @@ -11,7 +11,7 @@ public class CameoCommitService extends DefaultCommitService implements CommitService { @Override public boolean isProjectNew(String projectId) { - List commits = commitPersistence.findAllByProjectId(projectId); + List commits = commitPersistence.findByProjectAndRefAndTimestampAndLimit(projectId, "master", null, 2); return commits == null || commits.size() <= 1; // a cameo project gets 1 auto commit, so its still "new" } } diff --git a/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoNodeService.java b/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoNodeService.java index fc83864b6..4669d1ff8 100644 --- a/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoNodeService.java +++ b/cameo/src/main/java/org/openmbee/mms/cameo/services/CameoNodeService.java @@ -10,6 +10,7 @@ import org.openmbee.mms.core.services.HierarchicalNodeService; import org.openmbee.mms.core.services.NodeChangeInfo; import org.openmbee.mms.core.services.NodeGetInfo; +import org.openmbee.mms.crud.CrudConstants; import org.openmbee.mms.crud.services.DefaultNodeService; import org.openmbee.mms.json.CommitJson; import org.openmbee.mms.json.ElementJson; @@ -42,17 +43,17 @@ public void setMss(MethodSecurityService mss) { public ElementsResponse read(String projectId, String refId, ElementsRequest req, Map params) { - String commitId = params.getOrDefault(CameoConstants.COMMITID, null); + String commitId = params.getOrDefault(CrudConstants.COMMITID, null); if (commitId == null) { Optional commitJson = commitPersistence.findLatestByProjectAndRef(projectId, refId); if (!commitJson.isPresent()) { throw new InternalErrorException("Could not find latest commit for project and ref"); } - commitId = commitJson.get().getId(); + commitId = commitJson.get().getId(); } NodeGetInfo info = getNodePersistence().findAll(projectId, refId, commitId, req.getElements()); - + info.getActiveElementMap().values().forEach((e) -> e.setRefId(refId)); if (!info.getRejected().isEmpty()) { //continue looking in visible mounted projects for elements if not all found NodeGetInfo curInfo = info; @@ -61,9 +62,11 @@ public ElementsResponse read(String projectId, String refId, ElementsRequest req int i = 1; //0 is entry project, already gotten while (!curInfo.getRejected().isEmpty() && i < usages.size()) { + final int j = i; ElementsRequest reqNext = buildRequest(curInfo.getRejected().keySet()); //TODO use the right commitId in child if commitId is present in params :: same commit Id is not working for child curInfo = getNodePersistence().findAll(usages.get(i).getFirst(), usages.get(i).getSecond(), "", reqNext.getElements()); + curInfo.getActiveElementMap().values().forEach((e) -> e.setRefId(usages.get(j).getSecond())); info.getActiveElementMap().putAll(curInfo.getActiveElementMap()); curInfo.getActiveElementMap().forEach((id, json) -> info.getRejected().remove(id)); curInfo.getRejected().forEach((id, rejection) -> { @@ -78,6 +81,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(commitId); return response; } 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 ff85d0a3a..c0749c4a6 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 @@ -19,6 +19,7 @@ import org.openmbee.mms.core.objects.ElementsResponse; import org.openmbee.mms.core.services.NodeChangeInfo; import org.openmbee.mms.core.services.NodeGetInfo; +import org.openmbee.mms.crud.domain.JsonDomain; import org.openmbee.mms.json.ElementJson; import org.openmbee.mms.view.services.PropertyData; import org.openmbee.mms.view.services.ViewService; @@ -37,7 +38,7 @@ public ElementsResponse getDocuments(String projectId, String refId, Map parent = getFirstRelationshipOfType(projectId, refId, commitId, e, List.of(CameoNodeType.GROUP.getValue()), CameoConstants.OWNERID); parent.ifPresent(elementJson -> e.put(CameoConstants.SITECHARACTERIZATIONID, elementJson.getId())); - + } return res; } @@ -64,7 +65,7 @@ public void addChildViews(ElementsResponse res, Map params) { } ElementsResponse ownedAttributes = this.read(element.getProjectId(), element.getRefId(), buildRequest(ownedAttributeIds), params); - List filtered = filter(ownedAttributeIds, ownedAttributes.getElements()); + List filtered = JsonDomain.filter(ownedAttributeIds, ownedAttributes.getElements()); List childViews = new ArrayList<>(); for (ElementJson attr : filtered) { String childId = (String) attr.get(CameoConstants.TYPEID); @@ -86,8 +87,8 @@ public ElementsResponse getGroups(String projectId, String refId, Map groups = getNodePersistence().findAllByNodeType(projectId, refId, commitId, CameoNodeType.GROUP.getValue()); - ElementsResponse res = this.read(projectId, refId, buildRequestFromJsons(groups), params); - for (ElementJson e: res.getElements()) { + ElementsResponse res = new ElementsResponse().setElements(groups); + for (ElementJson e: groups) { Optional parent = getFirstRelationshipOfType(projectId, refId, commitId, e, List.of(CameoNodeType.GROUP.getValue()), CameoConstants.OWNERID); parent.ifPresent(elementJson -> e.put(CameoConstants.PARENTID, elementJson.getId())); diff --git a/core/src/main/java/org/openmbee/mms/core/builders/PermissionUpdatesResponseBuilder.java b/core/src/main/java/org/openmbee/mms/core/builders/PermissionUpdatesResponseBuilder.java index d2e7a42d3..4ed15275a 100644 --- a/core/src/main/java/org/openmbee/mms/core/builders/PermissionUpdatesResponseBuilder.java +++ b/core/src/main/java/org/openmbee/mms/core/builders/PermissionUpdatesResponseBuilder.java @@ -5,8 +5,8 @@ public class PermissionUpdatesResponseBuilder { - private Boolean inherit; - private Boolean isPublic; + protected Boolean inherit; + protected Boolean isPublic; private PermissionUpdateResponseBuilder usersBuilder = new PermissionUpdateResponseBuilder(); private PermissionUpdateResponseBuilder groupsBuilder = new PermissionUpdateResponseBuilder(); @@ -56,13 +56,10 @@ public PermissionUpdateResponseBuilder getGroups() { } private Boolean or(Boolean a, Boolean b) { - if(a == b) { - return a; - } - if(a == null) { + if (a == null) { return b; } - if(b == null) { + if (b == null) { return a; } return a || b; diff --git a/core/src/main/java/org/openmbee/mms/core/dao/CommitPersistence.java b/core/src/main/java/org/openmbee/mms/core/dao/CommitPersistence.java index c31357874..ee10a8c8d 100644 --- a/core/src/main/java/org/openmbee/mms/core/dao/CommitPersistence.java +++ b/core/src/main/java/org/openmbee/mms/core/dao/CommitPersistence.java @@ -23,7 +23,7 @@ public interface CommitPersistence { List findByProjectAndRefAndTimestampAndLimit(String projectId, String refId, Instant timestamp, int limit); - List elementHistory(String projectId, String elementId, Set commitDocIds); + List elementHistory(String projectId, String refId, String elementId); Optional deleteById(String projectId, String commitId); diff --git a/core/src/main/java/org/openmbee/mms/core/dao/NodePersistence.java b/core/src/main/java/org/openmbee/mms/core/dao/NodePersistence.java index be20c50d8..e06c7414c 100644 --- a/core/src/main/java/org/openmbee/mms/core/dao/NodePersistence.java +++ b/core/src/main/java/org/openmbee/mms/core/dao/NodePersistence.java @@ -21,7 +21,7 @@ public interface NodePersistence { NodeChangeInfo commitChanges(NodeChangeInfo nodeChangeInfo); - NodeGetInfo findById(String elementId, String refId, String commitId, String id); + NodeGetInfo findById(String projectId, String refId, String commitId, String elementId); List findAllByNodeType(String projectId, String refId, String commitId, int nodeType); diff --git a/core/src/main/java/org/openmbee/mms/core/services/DefaultPermissionService.java b/core/src/main/java/org/openmbee/mms/core/services/DefaultPermissionService.java index e743b505c..c53ad3dab 100644 --- a/core/src/main/java/org/openmbee/mms/core/services/DefaultPermissionService.java +++ b/core/src/main/java/org/openmbee/mms/core/services/DefaultPermissionService.java @@ -74,7 +74,7 @@ public void initProjectPerms(String projectId, boolean inherit, String creator) @Override public void initBranchPerms(String projectId, String branchId, boolean inherit, String creator) { - RefJson branch = getBranch(projectId, branchId, BRANCH_NOTFOUND_BEHAVIOR.CREATE); + RefJson branch = getBranch(projectId, branchId, BRANCH_NOTFOUND_BEHAVIOR.THROW); if(branch == null) { logger.error("Error initiating branch permissions " + projectId + " / " + branchId); throw new InternalErrorException("Could not initiate branch permissions"); @@ -166,7 +166,7 @@ public PermissionUpdateResponse updateBranchGroupPerms(PermissionUpdateRequest r @Override public PermissionUpdatesResponse setProjectInherit(boolean isInherit, String projectId) { PermissionUpdatesResponseBuilder responseBuilder = new PermissionUpdatesResponseBuilder(); - responseBuilder.setInherit(true); + responseBuilder.setInherit(isInherit); ProjectJson project = getProject(projectId); PermissionsDelegate permissionsDelegate = permissionsDelegateUtil.getPermissionsDelegate(project); if (permissionsDelegate.setInherit(isInherit)) { @@ -348,11 +348,13 @@ private RefJson getBranch(String projectId, String branchId, BRANCH_NOTFOUND_BEH switch (mode) { case THROW: throw new NotFoundException("Branch " + projectId + " " + branchId + " not found"); + /* branch should never be created here case CREATE: RefJson b = new RefJson(); b.setProjectId(projectId); b.setRefId(branchId); return branchPersistence.save(b); + */ default: //do nothing break; diff --git a/crud/src/main/java/org/openmbee/mms/crud/CrudConstants.java b/crud/src/main/java/org/openmbee/mms/crud/CrudConstants.java index 95e8a4f9e..642c8351a 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/CrudConstants.java +++ b/crud/src/main/java/org/openmbee/mms/crud/CrudConstants.java @@ -12,4 +12,5 @@ public class CrudConstants { public static final String PROJECT = "Project"; public static final String ORG = "Org"; public static final String CREATED = "created"; + public static final String CREATING = "creating"; } \ No newline at end of file diff --git a/crud/src/main/java/org/openmbee/mms/crud/controllers/branches/BranchesController.java b/crud/src/main/java/org/openmbee/mms/crud/controllers/branches/BranchesController.java index cc2eb6ef7..d69dcf0df 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/controllers/branches/BranchesController.java +++ b/crud/src/main/java/org/openmbee/mms/crud/controllers/branches/BranchesController.java @@ -74,7 +74,7 @@ public RefsResponse getRef( @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("@mss.hasProjectPrivilege(authentication, #projectId, 'PROJECT_CREATE_BRANCH', false)") - public RefsResponse createRefs( + public RefsResponse createRefs( //this can also handle update @PathVariable String projectId, @RequestBody RefsRequest projectsPost, Authentication auth) { @@ -92,24 +92,24 @@ public RefsResponse createRefs( response.addRejection(new Rejection(branch, 400, "Branch id is invalid.")); continue; } - - RefJson res; - branch.setCreator(auth.getName()); - if (branch.getParentCommitId() == null || branch.getParentCommitId().isEmpty()) { - Optional existingOptional = branchPersistence.findById(projectId, branch.getId()); - if (existingOptional.isPresent()) { - //Branch exists, should merge the json - branch.merge(existingOptional.get()); - res = branchService.updateBranch(projectId, branch); - } else { - res = branchService.createBranch(projectId, branch); + Optional existingOptional = branchPersistence.findById(projectId, branch.getId()); + if (existingOptional.isPresent()) { + //Branch exists, should merge the json, but cannot change parent ref or commit + //if branch exists it will get resurrected if it was deleted + RefJson existing = existingOptional.get(); + if (branch.getParentRefId() != null && !branch.getParentRefId().equals(existing.getParentRefId()) || + branch.getParentCommitId() != null && !branch.getParentCommitId().equals(existing.getParentCommitId())) { + response.addRejection(new Rejection(branch, 400, "Cannot change existing branch's origin")); + continue; } - } else { - //TODO implement branching from historical commit - response.addRejection(new Rejection(branch, 400, "Branching from historical commits is not implemented.")); + branch.merge(existingOptional.get()); + RefJson res = branchService.updateBranch(projectId, branch); + response.getRefs().add(res); continue; } - + RefJson res; + branch.setCreator(auth.getName()); + res = branchService.createBranch(projectId, branch); permissionService.initBranchPerms(projectId, branch.getId(), true, auth.getName()); response.getRefs().add(res); } catch (MMSException e) { diff --git a/crud/src/main/java/org/openmbee/mms/crud/controllers/projects/ProjectsController.java b/crud/src/main/java/org/openmbee/mms/crud/controllers/projects/ProjectsController.java index 095276dd0..7e9a2ab92 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/controllers/projects/ProjectsController.java +++ b/crud/src/main/java/org/openmbee/mms/crud/controllers/projects/ProjectsController.java @@ -103,8 +103,12 @@ public ProjectsResponse createOrUpdateProjects( } Optional existingOptional = projectPersistence.findById(json.getProjectId()); - if(existingOptional.isPresent()) { - //Project exists, should merge the json + if (existingOptional.isPresent()) { + //Project exists, should merge the json, but not if schema is different + if (json.getProjectType() != null && !json.getProjectType().equals(existingOptional.get().getProjectType())) { + response.addRejection(new Rejection(json, 400, "Cannot change existing project schema")); + continue; + } json.merge(existingOptional.get()); } else { //New Project @@ -141,25 +145,30 @@ public ProjectsResponse createOrUpdateProjects( response.addRejection(new Rejection(json, 403, "No permission to change project")); continue; } + boolean updatePermissions = false; if (json.getOrgId() != null && !json.getOrgId().isEmpty()) { - projectPersistence.findById(json.getProjectId()).ifPresent(projectJson -> { + Optional projectJsonOption = projectPersistence.findById(json.getProjectId()); + if (projectJsonOption.isPresent()) { + ProjectJson projectJson = projectJsonOption.get(); String existingOrg = projectJson.getOrgId(); if (!json.getOrgId().equals(existingOrg)) { if (!mss.hasProjectPrivilege(auth, json.getProjectId(), Privileges.PROJECT_DELETE.name(), false) || !mss.hasOrgPrivilege(auth, json.getOrgId(), Privileges.ORG_CREATE_PROJECT.name(), false)) { response.addRejection( new Rejection(json, 403, "No permission to move project org")); + continue; } if (projectPersistence.inheritsPermissions(projectJson.getProjectId())) { - permissionService.setProjectInherit(false, json.getProjectId()); - permissionService.setProjectInherit(true, json.getProjectId()); + updatePermissions = true; } } - - } - ); + } } response.getProjects().add(ps.update(json)); + if (updatePermissions) { + permissionService.setProjectInherit(false, json.getProjectId()); + permissionService.setProjectInherit(true, json.getProjectId()); + } } } catch (MMSException ex) { response.addRejection(new Rejection(json, ex.getCode().value(), ex.getMessageObject().toString())); diff --git a/crud/src/main/java/org/openmbee/mms/crud/domain/DefaultNodeUpdateFilter.java b/crud/src/main/java/org/openmbee/mms/crud/domain/DefaultNodeUpdateFilter.java index f283e05ce..7174db827 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/domain/DefaultNodeUpdateFilter.java +++ b/crud/src/main/java/org/openmbee/mms/crud/domain/DefaultNodeUpdateFilter.java @@ -23,7 +23,7 @@ public class DefaultNodeUpdateFilter implements NodeUpdateFilter { public boolean filterUpdate(NodeChangeInfo info, ElementJson updated, ElementJson existing) { if (!info.getOverwrite()) { if (Constants.TRUE.equals(existing.getIsDeleted()) || isUpdated(updated, existing, info)) { - diffUpdateJson(updated, existing, info); + return diffUpdateJson(updated, existing, info); } else { return false; } @@ -61,6 +61,7 @@ protected boolean diffUpdateJson(BaseJson element, Map existi } } element.merge(existing); + element.remove(ElementJson.IS_DELETED); return true; } diff --git a/crud/src/main/java/org/openmbee/mms/crud/domain/JsonDomain.java b/crud/src/main/java/org/openmbee/mms/crud/domain/JsonDomain.java index ed1a502fe..d5d9f51b4 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/domain/JsonDomain.java +++ b/crud/src/main/java/org/openmbee/mms/crud/domain/JsonDomain.java @@ -1,19 +1,27 @@ package org.openmbee.mms.crud.domain; import org.openmbee.mms.json.ElementJson; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; + +import java.util.*; public class JsonDomain { - public Map convertJsonToMap(List elements) { + public static List filter(List ids, List orig) { + Map map = convertJsonToMap(orig); + List ret = new ArrayList<>(); + for (String id: ids) { + if (map.containsKey(id)) { + ret.add(map.get(id)); + } + } + return ret; + } + public static Map convertJsonToMap(Collection elements) { if (elements == null || elements.isEmpty()) { return Collections.emptyMap(); } Map result = new HashMap<>(); - + for (ElementJson elem : elements) { if (elem == null) { continue; diff --git a/crud/src/main/java/org/openmbee/mms/crud/domain/NodeChangeDomain.java b/crud/src/main/java/org/openmbee/mms/crud/domain/NodeChangeDomain.java index 964276b48..f67329e26 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/domain/NodeChangeDomain.java +++ b/crud/src/main/java/org/openmbee/mms/crud/domain/NodeChangeDomain.java @@ -58,11 +58,12 @@ public void processElementAdded(NodeChangeInfo info, ElementJson element) { element.setCreated(commitJson.getCreated()); } - public void processElementUpdated(NodeChangeInfo info, ElementJson element, ElementJson existing) { - if(nodeUpdateFilters.stream().anyMatch(f -> !f.filterUpdate(info, element, existing))) { - return; + public boolean processElementUpdated(NodeChangeInfo info, ElementJson element, ElementJson existing) { + if (nodeUpdateFilters.stream().anyMatch(f -> !f.filterUpdate(info, element, existing))) { + return false; } processElementAddedOrUpdated(info, element); + return true; } protected void processElementAddedOrUpdated(NodeChangeInfo info, ElementJson element) { @@ -83,19 +84,10 @@ protected void processElementAddedOrUpdated(NodeChangeInfo info, ElementJson ele } public void processElementDeleted(NodeChangeInfo info, ElementJson element) { - //TODO Probably don't need this (see method below) - element.setIsDeleted("true"); } public NodeChangeInfo processDeleteJson(NodeChangeInfo info, Collection elements) { - - for(ElementJson element : elements) { - //TODO I don't think we need to do this by default, it shouldn't come back if deleted - if (Boolean.parseBoolean(element.getIsDeleted())) { - info.addRejection(element.getId(), new Rejection(element, 304, "Already deleted")); - continue; - } - + for (ElementJson element : elements) { ElementJson request = info.getReqElementMap().get(element.getId()); request.putAll(element); processElementDeleted(info, request); @@ -117,9 +109,6 @@ protected void rejectNotFound(NodeGetInfo info, String elementId) { public abstract NodeChangeInfo processPostJson(NodeChangeInfo nodeChangeInfo, Collection elements); - public void addExistingElements(NodeChangeInfo nodeChangeInfo, List existingElements) { - nodeGetDomain.addExistingElements(nodeChangeInfo, existingElements); - } public abstract void primeNodeChangeInfo(NodeChangeInfo nodeChangeInfo, Collection transactedElements); } diff --git a/crud/src/main/java/org/openmbee/mms/crud/services/DefaultBranchService.java b/crud/src/main/java/org/openmbee/mms/crud/services/DefaultBranchService.java index 0a38bd6ef..75471913c 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/services/DefaultBranchService.java +++ b/crud/src/main/java/org/openmbee/mms/crud/services/DefaultBranchService.java @@ -82,50 +82,56 @@ public RefJson createBranch(String projectId, RefJson branch) { branch.setCreated(Formats.FORMATTER.format(now)); branch.setDeleted(false); branch.setProjectId(projectId); - branch.setStatus(CrudConstants.CREATED); + branch.setStatus(CrudConstants.CREATING); //Ensure that the type is of Branch if (branch.getType() == null || branch.getType().isEmpty()) { branch.setType(Constants.BRANCH_TYPE); } - //Find parent branch String parentRefId; - if (branch.getParentRefId() != null) { + Optional parentCommit = null; + if (branch.getParentCommitId() != null && !branch.getParentCommitId().isEmpty()) { + parentCommit = commitPersistence.findById(projectId, branch.getParentCommitId()); + if (!parentCommit.isPresent()) { + throw new BadRequestException("Parent commit cannot be determined or found"); + } + parentRefId = parentCommit.get().getRefId(); + branch.setParentRefId(parentRefId); + } else if (branch.getParentRefId() != null && !branch.getParentRefId().isEmpty()) { parentRefId = branch.getParentRefId(); } else { parentRefId = Constants.MASTER_BRANCH; branch.setParentRefId(parentRefId); } Optional parentRefOption = branchPersistence.findById(projectId, parentRefId); - if(!parentRefOption.isPresent()) { + if (!parentRefOption.isPresent()) { throw new BadRequestException("Parent branch cannot be determined"); } //Find parent commit // AND the commit federated are expecting the branches to be in PG - Optional parentCommit; - if(branch.getParentCommitId() != null) { - parentCommit = commitPersistence.findById(projectId, branch.getParentCommitId()); - } else { + if (parentCommit == null || !parentCommit.isPresent()) { parentCommit = commitPersistence.findLatestByProjectAndRef(projectId, parentRefId); parentCommit.ifPresent(parent -> branch.setParentCommitId(parent.getId()) ); } - if(!parentCommit.isPresent()) { - throw new BadRequestException("Parent commit cannot be determined"); + if (!parentCommit.isPresent()) { + throw new BadRequestException("Parent commit cannot be determined or found"); } //Do branch creation try { RefJson committedBranch = branchPersistence.save(branch); nodePersistence.branchElements(parentRefOption.get(), parentCommit.get(), committedBranch); + committedBranch.setStatus(CrudConstants.CREATED); + branchPersistence.update(committedBranch); //TODO transaction commit eventPublisher.forEach(pub -> pub.publish( EventObject.create(projectId, committedBranch.getId(), "branch_created", committedBranch))); - return branch; + return committedBranch; } catch (Exception e) { //TODO transaction rollback logger.error("Couldn't create branch: {}", branch.getId(), e); diff --git a/crud/src/main/java/org/openmbee/mms/crud/services/DefaultCommitService.java b/crud/src/main/java/org/openmbee/mms/crud/services/DefaultCommitService.java index 7a7b07275..ec3224910 100644 --- a/crud/src/main/java/org/openmbee/mms/crud/services/DefaultCommitService.java +++ b/crud/src/main/java/org/openmbee/mms/crud/services/DefaultCommitService.java @@ -85,12 +85,7 @@ public CommitsResponse getElementCommits(String projectId, String refId, String if (!ref.isPresent()) { throw new NotFoundException("Branch not found"); } - List refCommits = commitPersistence.findByProjectAndRefAndTimestampAndLimit(projectId, refId, null, 0); - Set commitIds = new LinkedHashSet<>(); - for (CommitJson commit: refCommits) { - commitIds.add(commit.getId()); - } - res.getCommits().addAll(commitPersistence.elementHistory(projectId, elementId, commitIds)); + res.getCommits().addAll(commitPersistence.elementHistory(projectId, refId, elementId)); return res; } @@ -112,7 +107,8 @@ public CommitsResponse getCommits(String projectId, CommitsRequest req) { @Override public boolean isProjectNew(String projectId) { - List commits = commitPersistence.findAllByProjectId(projectId); + // if project is not new, there must be at least 1 commit to master + List commits = commitPersistence.findByProjectAndRefAndTimestampAndLimit(projectId, "master", null, 1); return commits == null || commits.isEmpty(); } } 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 3a2b803a6..671581132 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 @@ -94,6 +94,11 @@ public void readAsStream(String projectId, String refId, Map par public ElementsResponse read(String projectId, String refId, String id, Map params) { + if (id != null && !id.isEmpty()) { + logger.debug("ElementId given: {}", id); + ElementsRequest req = buildRequest(id); + return read(projectId, refId, req, params); + } String commitId = params.getOrDefault(CrudConstants.COMMITID, null); if (commitId == null) { Optional commitJson = commitPersistence.findLatestByProjectAndRef(projectId, refId); @@ -102,26 +107,14 @@ public ElementsResponse read(String projectId, String refId, String id, } commitId = commitJson.get().getId(); } - + // If no id is provided, return all ElementsResponse response = new ElementsResponse(); - if (id != null && !id.isEmpty()) { - logger.debug("ElementId given: {}", id); - - NodeGetInfo getInfo = nodePersistence.findById(projectId, refId, commitId, id); - if (!getInfo.getRejected().isEmpty()) { - response.addRejection(getInfo.getRejected().get(id)); - } else { - response.getElements().add(getInfo.getActiveElementMap().get(id)); - } + logger.debug("No ElementId given"); - } else { - // If no id is provided, return all - logger.debug("No ElementId given"); - - List nodes = nodePersistence.findAll(projectId, refId, commitId); - response.getElements().addAll(nodes); - } + List nodes = nodePersistence.findAll(projectId, refId, commitId); + response.getElements().addAll(nodes); response.getElements().forEach(v -> v.setRefId(refId)); + response.setCommitId(commitId); return response; } @@ -130,11 +123,21 @@ public ElementsResponse read(String projectId, String refId, ElementsRequest req Map params) { String commitId = params.getOrDefault(CrudConstants.COMMITID, null); + if (commitId == null) { + Optional commitJson = commitPersistence.findLatestByProjectAndRef(projectId, refId); + if (!commitJson.isPresent()) { + throw new InternalErrorException("Could not find latest commit for project and ref"); + } + commitId = commitJson.get().getId(); + } + NodeGetInfo info = nodePersistence.findAll(projectId, refId, commitId, req.getElements()); ElementsResponse response = new ElementsResponse(); response.getElements().addAll(info.getActiveElementMap().values()); + response.getElements().forEach(v -> v.setRefId(refId)); response.setRejected(new ArrayList<>(info.getRejected().values())); + response.setCommitId(commitId); return response; } @@ -158,10 +161,10 @@ public ElementsCommitResponse createOrUpdate(String projectId, String refId, Ele overwriteJson, preserveTimestamps); changes = nodePersistence.prepareAddsUpdates(changes, req.getElements()); - for(ElementJson element : changes.getUpdatedMap().values()) { + for (ElementJson element : changes.getUpdatedMap().values()) { extraProcessPostedElement(changes, element); } - if(req.getDeletes() != null) { + if (req.getDeletes() != null) { changes = nodePersistence.prepareDeletes(changes, req.getDeletes()); } @@ -240,34 +243,10 @@ private CommitJson createCommit(String creator, String refId, String projectId, cmjs.setSource(req.getSource()); cmjs.setRefId(refId); cmjs.setProjectId(projectId); - if(commitId != null) { - cmjs.setCommitId(commitId); + if (commitId != null) { + cmjs.setId(commitId); + cmjs.setDocId(commitId); } return cmjs; } - - protected List filter(List ids, List orig) { - Map map = convertJsonToMap(orig); - List ret = new ArrayList<>(); - for (String id: ids) { - if (map.containsKey(id)) { - ret.add(map.get(id)); - } - } - return ret; - } - - protected Map convertJsonToMap(List elements) { - Map result = new HashMap<>(); - for (ElementJson elem : elements) { - if (elem == null) { - continue; - } - if (elem.getId() != null && !elem.getId().isBlank()) { - result.put(elem.getId(), elem); - } - } - return result; - } - } diff --git a/data/data.gradle b/data/data.gradle index 2771c7eef..cce0e85d9 100644 --- a/data/data.gradle +++ b/data/data.gradle @@ -13,4 +13,4 @@ dependencies { api commonDependencies.'hibernate-core' testImplementation commonDependencies.'spring-boot-starter-test' -} +} \ No newline at end of file diff --git a/data/src/main/java/org/openmbee/mms/data/dao/CommitIndexDAO.java b/data/src/main/java/org/openmbee/mms/data/dao/CommitIndexDAO.java index abd1c8e0e..d8c86a79b 100644 --- a/data/src/main/java/org/openmbee/mms/data/dao/CommitIndexDAO.java +++ b/data/src/main/java/org/openmbee/mms/data/dao/CommitIndexDAO.java @@ -25,6 +25,8 @@ public interface CommitIndexDAO { List elementHistory(String id, Set commitIds); + List elementDeletedHistory(String id, Collection commitIds); + CommitJson update(CommitJson commitJson); } diff --git a/docs/conf.py b/docs/conf.py index 24beaec43..877a104e7 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ master_doc = 'index' # The full version, including alpha/beta/rc tags -release = '4.0.19' +release = '4.0.20' # -- General configuration --------------------------------------------------- @@ -57,4 +57,4 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ['_static'] \ No newline at end of file diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 000000000..52b04f2ec --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +sphinx_rtd_theme \ No newline at end of file diff --git a/elastic/README.rst b/elastic/README.rst index fb849369d..eec5cf46e 100644 --- a/elastic/README.rst +++ b/elastic/README.rst @@ -21,6 +21,16 @@ The following are a list of options to configure the Elastic Module for MMS. elasticsearch.http The transport protocol to use to connect to the Elasticsearch server or cluster. Required. + elasticsearch.username + Username, Optional. + + | `Default: null` + + elasticsearch.password + Password, Optional. + + | `Default: null` + elasticsearch.limit.result The maximum number of results a single search request should return. Optional. diff --git a/elastic/src/main/java/org/openmbee/mms/elastic/CommitElasticDAOImpl.java b/elastic/src/main/java/org/openmbee/mms/elastic/CommitElasticDAOImpl.java index 0b3f73268..2be63696b 100644 --- a/elastic/src/main/java/org/openmbee/mms/elastic/CommitElasticDAOImpl.java +++ b/elastic/src/main/java/org/openmbee/mms/elastic/CommitElasticDAOImpl.java @@ -123,6 +123,33 @@ private QueryBuilder getCommitHistoryQuery(String id, Set commitIds) { return query; } + @Override + public List elementDeletedHistory(String id, Collection commitIds) { + QueryBuilder query = QueryBuilders.boolQuery() + .filter(QueryBuilders.termQuery("deleted.id", id)) + .filter(QueryBuilders.termsQuery(CommitJson.ID, commitIds)); + try { + List commits = new ArrayList<>(); + SearchHits hits = getCommitResults(query); + if (hits.getTotalHits().value == 0) { + return new ArrayList<>(); + } + for (SearchHit hit : hits.getHits()) { + Map source = hit.getSourceAsMap();// gets "_source" + CommitJson ob = newInstance(); + ob.putAll(source); + ob.remove(CommitJson.ADDED); + ob.remove(CommitJson.UPDATED); + ob.remove(CommitJson.DELETED); + commits.add(ob); + } + return commits; + } catch (IOException e) { + logger.error(e.getMessage(), e); + throw new InternalErrorException(e); + } + } + /** * Returns the commit history of a element *

Returns a list of commit metadata for the specified id @@ -173,14 +200,18 @@ private List getDocs(String commitId) { QueryBuilder commitQuery = QueryBuilders.boolQuery() .filter(QueryBuilders.termQuery(CommitJson.ID, commitId)); SearchHits hits = getCommitResults(commitQuery); - if (hits.getTotalHits().value == 0) { - return new ArrayList<>(); - } List rawCommits = new ArrayList<>(); - for (SearchHit hit : hits.getHits()) { - CommitJson ob = new CommitJson(); - ob.putAll(hit.getSourceAsMap()); - rawCommits.add(ob); // gets "_source" + if (hits.getTotalHits().value > 0) { + for (SearchHit hit : hits.getHits()) { + CommitJson ob = new CommitJson(); + ob.putAll(hit.getSourceAsMap()); + rawCommits.add(ob); // gets "_source" + } + } + if (rawCommits.isEmpty()) { + //try getting directly using id + Optional c = super.findById(this.getIndex(), commitId); + c.ifPresent(commit -> rawCommits.add(commit)); } return rawCommits; } catch (IOException ioe) { diff --git a/elastic/src/main/java/org/openmbee/mms/elastic/config/ElasticsearchConfig.java b/elastic/src/main/java/org/openmbee/mms/elastic/config/ElasticsearchConfig.java index 66e92cc69..be2380345 100644 --- a/elastic/src/main/java/org/openmbee/mms/elastic/config/ElasticsearchConfig.java +++ b/elastic/src/main/java/org/openmbee/mms/elastic/config/ElasticsearchConfig.java @@ -24,15 +24,15 @@ public class ElasticsearchConfig { @Value("${elasticsearch.http}") private String elasticsearchHttp; - @Value("${elasticsearch.password}") + @Value("${elasticsearch.password:#{null}}") private String elasticsearchPassword; - @Value("${elasticsearch.username}") + @Value("${elasticsearch.username:#{null}}") private String elasticsearchUsername; @Bean(name = "clientElastic", destroyMethod = "close") public RestHighLevelClient restClient() { - + RestClientBuilder builder = RestClient.builder(new HttpHost(elasticsearchHost, elasticsearchPort, elasticsearchHttp)); builder.setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder.setConnectTimeout(10000).setSocketTimeout(1000000)); diff --git a/example/example.gradle b/example/example.gradle index 370165470..e25098d06 100644 --- a/example/example.gradle +++ b/example/example.gradle @@ -49,6 +49,6 @@ configurations { } } bootJar { - duplicatesStrategy = DuplicatesStrategy.INCLUDE + duplicatesStrategy = DuplicatesStrategy.WARN } ext['elasticsearch.version'] = "$elasticVersion" diff --git a/example/getAtCommits.postman_collection.json b/example/getAtCommits.postman_collection.json new file mode 100644 index 000000000..db2bb4538 --- /dev/null +++ b/example/getAtCommits.postman_collection.json @@ -0,0 +1,884 @@ +{ + "info": { + "_postman_id": "c3e5107f-904c-47a4-8c31-e6bfa70f9ac4", + "name": "GetAtCommits", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "7302261" + }, + "item": [ + { + "name": "login using admin", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " ", + "});", + "", + "pm.test(\"response has token\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.token).to.be.a('string');", + " pm.environment.set(\"token\", jsonData.token);", + "", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"username\": \"{{adminUsername}}\",\n\t\"password\": \"{{adminPassword}}\"\n}" + }, + "url": { + "raw": "{{host}}/authentication", + "host": [ + "{{host}}" + ], + "path": [ + "authentication" + ] + } + }, + "response": [] + }, + { + "name": "add org", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has org commits\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.orgs[0].id).to.eql('commits');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"orgs\": [\n\t\t{\n\t\t\t\"id\": \"commits\",\n\t\t\t\"name\": \"commits\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/orgs", + "host": [ + "{{host}}" + ], + "path": [ + "orgs" + ] + } + }, + "response": [] + }, + { + "name": "add project", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has project commits\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.projects[0].id).to.eql('commits');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"projects\": [\n\t\t{\n\t\t\t\"id\": \"commits\", \n\t\t\t\"name\": \"commits\",\n\t\t\t\"orgId\": \"commits\",\n\t\t\t\"schema\": \"default\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects", + "host": [ + "{{host}}" + ], + "path": [ + "projects" + ] + } + }, + "response": [] + }, + { + "name": "add a and b", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(2);", + "});", + "", + "pm.environment.set(\"addABCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"a\",\n\t\t\t\"name\": \"a\"\n\t\t}, {\n\t\t\t\"id\": \"b\", \n\t\t\t\"name\": \"b\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "add c", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"addCCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"c\",\n\t\t\t\"name\": \"c\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "add d", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"addDCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"d\",\n\t\t\t\"name\": \"d\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "delete a", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"deleteACommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements/a", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements", + "a" + ] + } + }, + "response": [] + }, + { + "name": "update b", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"updateBCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n {\n\t\t\t\"id\": \"b\", \n\t\t\t\"name\": \"b updated\"\n\t\t}\n\t]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "delete c", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"deleteCCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n {\n\t\t\t\"id\": \"c\"\n\t\t}\n\t]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "add e", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"addECommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"e\",\n\t\t\t\"name\": \"e\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "recurrect c", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"resurrectCCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"c\",\n\t\t\t\"name\": \"c\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "get elements at initial commit", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has a and b\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(2);", + " var result = jsonData.elements.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.have.members([{id: 'a'}, {id: 'b'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('addABCommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements?commitId={{addABCommitId}}", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ], + "query": [ + { + "key": "commitId", + "value": "{{addABCommitId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "get elements at add d", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has a,b,c,d\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(4);", + " var result = jsonData.elements.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.have.members([{id: 'a'}, {id: 'b'}, {id: 'c'}, {id: 'd'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('addDCommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements?commitId={{addDCommitId}}", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ], + "query": [ + { + "key": "commitId", + "value": "{{addDCommitId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "get elements at delete a", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has b,c,d\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(3);", + " var result = jsonData.elements.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.have.members([{id: 'b'}, {id: 'c'}, {id: 'd'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('deleteACommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements?commitId={{deleteACommitId}}", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ], + "query": [ + { + "key": "commitId", + "value": "{{deleteACommitId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "get elements at update b", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has b,c,d with updated b name\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(3);", + " var result = jsonData.elements.map(e => ({id: e.id, name: e.name}));", + " pm.expect(result).to.deep.have.members([{id: 'b', name: 'b updated'}, {id: 'c', name: 'c'}, {id: 'd', name: 'd'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('updateBCommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements?commitId={{updateBCommitId}}", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ], + "query": [ + { + "key": "commitId", + "value": "{{updateBCommitId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "get elements at add e", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has b,d,e\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(3);", + " var result = jsonData.elements.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.have.members([{id: 'b'}, {id: 'd'}, {id: 'e'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('addECommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements?commitId={{addECommitId}}", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ], + "query": [ + { + "key": "commitId", + "value": "{{addECommitId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "get elements at resurrect c", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has b,c,d,e\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(4);", + " var result = jsonData.elements.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.have.members([{id: 'b'}, {id: 'c'}, {id: 'd'}, {id: 'e'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('resurrectCCommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/commits/refs/master/elements?commitId={{resurrectCCommitId}}", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "commits", + "refs", + "master", + "elements" + ], + "query": [ + { + "key": "commitId", + "value": "{{resurrectCCommitId}}" + } + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{token}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] +} \ No newline at end of file diff --git a/example/makeBranchFromCommit.postman_collection.json b/example/makeBranchFromCommit.postman_collection.json new file mode 100644 index 000000000..6d863f1a7 --- /dev/null +++ b/example/makeBranchFromCommit.postman_collection.json @@ -0,0 +1,1025 @@ +{ + "info": { + "_postman_id": "1ddbdc4a-79cc-4bec-8118-7e600e908b38", + "name": "MakeBranchFromCommit", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "3693486" + }, + "item": [ + { + "name": "login using admin", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "", + "pm.test(\"Status code is 200\", function () {", + " pm.response.to.have.status(200);", + " ", + "});", + "", + "pm.test(\"response has token\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.token).to.be.a('string');", + " pm.environment.set(\"token\", jsonData.token);", + "", + "});", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "auth": { + "type": "noauth" + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"username\": \"{{adminUsername}}\",\n\t\"password\": \"{{adminPassword}}\"\n}" + }, + "url": { + "raw": "{{host}}/authentication", + "host": [ + "{{host}}" + ], + "path": [ + "authentication" + ] + } + }, + "response": [] + }, + { + "name": "add org", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has org branch_from_commit\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.orgs[0].id).to.eql('branch_from_commit_org');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"orgs\": [\n\t\t{\n\t\t\t\"id\": \"branch_from_commit_org\",\n\t\t\t\"name\": \"branch_from_commit_org\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/orgs", + "host": [ + "{{host}}" + ], + "path": [ + "orgs" + ] + } + }, + "response": [] + }, + { + "name": "add project", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has project branch_from_commit\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.projects[0].id).to.eql('branch_from_commit');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"projects\": [\n\t\t{\n\t\t\t\"id\": \"branch_from_commit\", \n\t\t\t\"name\": \"branch_from_commit\",\n\t\t\t\"orgId\": \"branch_from_commit_org\",\n\t\t\t\"schema\": \"default\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects", + "host": [ + "{{host}}" + ], + "path": [ + "projects" + ] + } + }, + "response": [] + }, + { + "name": "add a and b to master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(2);", + "});", + "", + "pm.environment.set(\"addABCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"a\",\n\t\t\t\"name\": \"a\"\n\t\t}, {\n\t\t\t\"id\": \"b\", \n\t\t\t\"name\": \"b\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "add c to master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"addCCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"c\",\n\t\t\t\"name\": \"c\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "add d to master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"addDCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"d\",\n\t\t\t\"name\": \"d\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "delete a in master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"deleteACommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements/a", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements", + "a" + ] + } + }, + "response": [] + }, + { + "name": "update b in master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"updateBCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n {\n\t\t\t\"id\": \"b\", \n\t\t\t\"name\": \"b updated\"\n\t\t}\n\t]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "delete c in master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"deleteCCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n {\n\t\t\t\"id\": \"c\"\n\t\t}\n\t]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "add e to master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"addECommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"e\",\n\t\t\t\"name\": \"e\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "recurrect c in master", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has elements\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.elements.length).to.eql(1);", + "});", + "", + "pm.environment.set(\"resurrectCCommitId\", pm.response.json().commitId);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"elements\": [\n\t\t{\n\t\t\t\"id\": \"c\",\n\t\t\t\"name\": \"c\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/master/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "master", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "create branch from \"add d to master\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"branch created with right parentRef and commit id\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.refs[0].id).to.eql('addDCommitId_branch');", + " pm.expect(jsonData.refs[0].parentRefId).to.eql('master');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"refs\": [\n\t\t{\n\t\t\t\"id\": \"addDCommitId_branch\",\n\t\t\t\"name\": \"addDCommitId_branch\",\n\t\t\t\"type\": \"Branch\",\n\t\t\t\"parentCommitId\": \"{{addDCommitId}}\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs" + ] + } + }, + "response": [] + }, + { + "name": "create branch from \"delete c\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"branch created with right parentRef and commit id\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.refs[0].id).to.eql('deleteCCommitId_branch');", + " pm.expect(jsonData.refs[0].parentRefId).to.eql('master');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"refs\": [\n\t\t{\n\t\t\t\"id\": \"deleteCCommitId_branch\",\n\t\t\t\"name\": \"deleteCCommitId_branch\",\n\t\t\t\"type\": \"Branch\",\n\t\t\t\"parentCommitId\": \"{{deleteCCommitId}}\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs" + ] + } + }, + "response": [] + }, + { + "name": "create branch from \"resurrect c\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"branch created with right parentRef and commit id\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.refs[0].id).to.eql('resurrectCCommitId_branch');", + " pm.expect(jsonData.refs[0].parentRefId).to.eql('master');", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"refs\": [\n\t\t{\n\t\t\t\"id\": \"resurrectCCommitId_branch\",\n\t\t\t\"name\": \"resurrectCCommitId_branch\",\n\t\t\t\"type\": \"Branch\",\n\t\t\t\"parentCommitId\": \"{{resurrectCCommitId}}\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs" + ] + } + }, + "response": [] + }, + { + "name": "try to change parentCommitId on existing branch", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"400 response\", function () {", + " pm.response.to.have.status(400);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"refs\": [\n\t\t{\n\t\t\t\"id\": \"resurrectCCommitId_branch\",\n\t\t\t\"name\": \"resurrectCCommitId_branch\",\n\t\t\t\"type\": \"Branch\",\n\t\t\t\"parentCommitId\": \"{{deleteCCommitId}}\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs" + ] + } + }, + "response": [] + }, + { + "name": "add more metadata to existing branch", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"200 response\", function () {", + " pm.response.to.have.status(200);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"refs\": [\n\t\t{\n\t\t\t\"id\": \"resurrectCCommitId_branch\",\n\t\t\t\"name\": \"resurrectCCommitId_branch\",\n\t\t\t\"type\": \"Branch\",\n\t\t\t\"newAttribute\": \"new data\"\n\t\t}\n\t]\n}" + }, + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs" + ] + } + }, + "response": [] + }, + { + "name": "get elements from branch from \"add d to master\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has a,b,c,d\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(4);", + " var result = jsonData.elements.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.have.members([{id: 'a'}, {id: 'b'}, {id: 'c'}, {id: 'd'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('addDCommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/addDCommitId_branch/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "addDCommitId_branch", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "get elements from branch from \"delete c\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has b,d\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(2);", + " var result = jsonData.elements.map(e => ({id: e.id, name: e.name}));", + " pm.expect(result).to.deep.have.members([{id: 'b', name: 'b updated'}, {id: 'd', name: 'd'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('deleteCCommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/deleteCCommitId_branch/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "deleteCCommitId_branch", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "get elements from branch from \"resurrect c\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has b,c,d,e\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.elements.length).to.eql(4);", + " var result = jsonData.elements.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.have.members([{id: 'b'}, {id: 'c'}, {id: 'd'}, {id: 'e'}]);", + " pm.expect(jsonData.commitId).to.eql(pm.environment.get('resurrectCCommitId'));", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/resurrectCCommitId_branch/elements", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "resurrectCCommitId_branch", + "elements" + ] + } + }, + "response": [] + }, + { + "name": "get commits from \"add d to master\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has right commit history\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.commits.length).to.eql(3);", + " var result = jsonData.commits.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.include.ordered.members([", + " {id: pm.environment.get('addDCommitId')}, ", + " {id: pm.environment.get('addCCommitId')}, ", + " {id: pm.environment.get('addABCommitId')}", + " ]);", + " ", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/addDCommitId_branch/commits", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "addDCommitId_branch", + "commits" + ] + } + }, + "response": [] + }, + { + "name": "get commits from \"delete c\"", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"response has right commit history\", function () {", + " var jsonData = pm.response.json();", + "", + " pm.expect(jsonData.commits.length).to.eql(6);", + " var result = jsonData.commits.map(e => ({id: e.id}));", + " pm.expect(result).to.deep.include.ordered.members([", + " {id: pm.environment.get('deleteCCommitId')},", + " {id: pm.environment.get('updateBCommitId')},", + " {id: pm.environment.get('deleteACommitId')},", + " {id: pm.environment.get('addDCommitId')}, ", + " {id: pm.environment.get('addCCommitId')}, ", + " {id: pm.environment.get('addABCommitId')},", + " ]);", + "", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{host}}/projects/branch_from_commit/refs/deleteCCommitId_branch/commits", + "host": [ + "{{host}}" + ], + "path": [ + "projects", + "branch_from_commit", + "refs", + "deleteCCommitId_branch", + "commits" + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "{{token}}", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] +} \ No newline at end of file diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedBranchPersistence.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedBranchPersistence.java index b346c5da4..bfc586066 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedBranchPersistence.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedBranchPersistence.java @@ -44,7 +44,7 @@ public FederatedBranchPersistence(BranchDAO branchDAO, BranchGDAO branchGDAO, Br @Override public RefJson save(RefJson refJson) { //Master branch special case - boolean isMasterBranch = refJson.getName().equals(Constants.MASTER_BRANCH); + boolean isMasterBranch = refJson.getId().equals(Constants.MASTER_BRANCH); //Fill in docId if (refJson.getDocId() == null || refJson.getDocId().isEmpty()) { @@ -72,7 +72,7 @@ public RefJson save(RefJson refJson) { globalBranch.setInherit(true); //Master branch case. Can skip parent branch and parent commit check - if(!isMasterBranch) { + if (!isMasterBranch) { //Validate parent branch Optional refOption = branchDAO.findByBranchId(scopedBranch.getParentRefId()); if (!refOption.isPresent()) { @@ -80,18 +80,9 @@ public RefJson save(RefJson refJson) { } //Validate parent commit - Optional parentCommit = commitDAO.findLatestByRef(refOption.get()); + Optional parentCommit = commitDAO.findByCommitId(refJson.getParentCommitId()); if (!parentCommit.isPresent()) { - throw new InternalErrorException("Cannot determine latest commit of branch."); - } - - if (refJson.getParentCommitId() != null) { - if (!refJson.getParentCommitId().equals(parentCommit.get().getCommitId())) { - //This DAO cannot create branches from historic versions - throw new BadRequestException("Internal Error: Invalid branch creation logic."); - } - } else { - refJson.setParentCommitId(parentCommit.get().getCommitId()); + throw new InternalErrorException("Cannot determine parent commit."); } parentCommit.ifPresent(parent -> scopedBranch.setParentCommit(parent.getId())); } @@ -109,7 +100,12 @@ public RefJson save(RefJson refJson) { @Override public RefJson update(RefJson refJson) { - return save(refJson); + ContextHolder.setContext(refJson.getProjectId()); + Optional existing = branchDAO.findByBranchId(refJson.getId()); + existing.get().setDeleted(refJson.isDeleted()); + branchDAO.save(existing.get()); + branchIndexDAO.update(refJson); + return refJson; } @Override diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedCommitPersistence.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedCommitPersistence.java index 75b01ec77..9b3abc81d 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedCommitPersistence.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedCommitPersistence.java @@ -41,7 +41,7 @@ public CommitJson save(CommitJson commitJson, Instant now) { ContextHolder.setContext(commitJson.getProjectId()); Commit commit = new Commit(); commit.setComment(commitJson.getComment()); - commit.setCommitId(commitJson.getDocId()); + commit.setCommitId(commitJson.getId()); commit.setCreator(commitJson.getCreator()); commit.setBranchId(commitJson.getRefId()); commit.setCommitType(CommitType.COMMIT); @@ -54,7 +54,11 @@ public CommitJson save(CommitJson commitJson, Instant now) { } catch (Exception e) { logger.error("Couldn't create commit: {}", commitJson.getId(), e); //Need to clean up in case of partial creation - deleteById(commitJson.getProjectId(), commitJson.getId()); + try { + deleteById(commitJson.getProjectId(), commitJson.getId()); + } catch (Exception ex) { + logger.error("Commit cleanup error: ", ex); + } throw new InternalErrorException("Could not create commit"); } } @@ -68,10 +72,10 @@ public CommitJson update(CommitJson commitJson) { if (commitOptional.isPresent()) { Instant now = Instant.now(); commitJson.setModified(Formats.FORMATTER.format(now)); - + commitJson.setDocId(commitJson.getId()); Commit commit = commitOptional.get(); commit.setComment(commitJson.getComment()); - commit.setTimestamp(now); + //commit.setTimestamp(now); commitDAO.save(commit); return commitIndexDAO.update(commitJson); } @@ -106,7 +110,7 @@ public List findAllById(String projectId, Set commitIds) { } }); List commits = commitIndexDAO.findAllById(foundCommitIds); - commits.sort(Comparator.comparing(BaseJson::getCreated)); + commits.sort(Comparator.comparing(CommitJson::getCreated).reversed()); return commits; } @@ -157,27 +161,33 @@ public List findByProjectAndRefAndTimestampAndLimit(String projectId } @Override - public List elementHistory(String projectId, String elementId, Set commitDocIds) { + public List elementHistory(String projectId, String refId, String elementId) { ContextHolder.setContext(projectId); - List commits = commitIndexDAO.elementHistory(elementId, commitDocIds); + Optional branchOptional = branchDAO.findByBranchId(refId); + if(!branchOptional.isPresent()) { + return new ArrayList<>(); + } + Branch b = branchOptional.get(); + List commitList = commitDAO.findByRefAndTimestampAndLimit(b, null, 0); + Set commitIds = new HashSet<>(); + for (Commit commit: commitList) { + commitIds.add(commit.getCommitId()); + } + List commits = commitIndexDAO.elementHistory(elementId, commitIds); commits.sort(Comparator.comparing(CommitJson::getCreated).reversed()); return commits; } @Override public Optional deleteById(String projectId, String commitId) { + // this is used for potentially cleaning up a failed commit save + // should not be used intentionally ContextHolder.setContext(projectId); - Optional commitOptional = commitDAO.findByCommitId(commitId); - try { - Optional commitJsonOptional = commitOptional.isPresent() ? - commitIndexDAO.findById(commitOptional.get().getCommitId()) : Optional.empty(); - if (commitJsonOptional.isPresent()) { - commitIndexDAO.deleteById(commitJsonOptional.get().getDocId()); - return commitJsonOptional; - } - } catch (Exception e) { - throw new InternalErrorException("Could not delete commit"); + Optional commitJsonOptional = commitIndexDAO.findById(commitId); + if (commitJsonOptional.isPresent()) { + commitIndexDAO.deleteById(commitId); + return commitJsonOptional; } - throw new NotFoundException("Could not delete commit"); + return Optional.empty(); } } diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedNodePersistence.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedNodePersistence.java index b7d227120..446d8499c 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedNodePersistence.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedNodePersistence.java @@ -112,40 +112,34 @@ public NodeGetInfo findById(String projectId, String refId, String commitId, Str @Override public List findAllByNodeType(String projectId, String refId, String commitId, int nodeType) { ContextHolder.setContext(projectId, refId); - Optional branch = branchDAO.findByBranchId(refId); - validateBranch(branch); + String commitToPass = checkCommit(refId, commitId); List nodes; - Optional latestCommit = commitDAO.findLatestByRef(branch.get()); - if (commitId != null && !commitId.isEmpty() && !commitId.equals(latestCommit.map(Commit::getCommitId).orElse(null))) { - validateCommit(commitDAO.findByCommitId(commitId)); + if (commitToPass != null) { nodes = nodeDAO.findAllByNodeType(nodeType); } else { nodes = nodeDAO.findAllByDeletedAndNodeType(false, nodeType); } - return new ArrayList<>(getNodeGetDomain().processGetJsonFromNodes(nodes, commitId).getActiveElementMap().values()); + return new ArrayList<>(getNodeGetDomain().processGetJsonFromNodes(nodes, commitToPass).getActiveElementMap().values()); } - + @Override public NodeGetInfo findAll(String projectId, String refId, String commitId, List elements) { ContextHolder.setContext(projectId, refId); - return getNodeGetDomain().processGetJson(elements, commitId); + return getNodeGetDomain().processGetJson(elements, checkCommit(refId, commitId)); } @Override public List findAll(String projectId, String refId, String commitId) { ContextHolder.setContext(projectId, refId); - Optional branch = branchDAO.findByBranchId(refId); - validateBranch(branch); List nodes; - Optional latestCommit = commitDAO.findLatestByRef(branch.get()); - if (commitId != null && !commitId.isEmpty() && !commitId.equals(latestCommit.map(Commit::getCommitId).orElse(null))) { - validateCommit(commitDAO.findByCommitId(commitId)); + String commitToPass = checkCommit(refId, commitId); + if (commitToPass != null) { nodes = nodeDAO.findAll(); } else { nodes = nodeDAO.findAllByDeleted(false); } - return new ArrayList<>(getNodeGetDomain().processGetJsonFromNodes(nodes, commitId).getActiveElementMap().values()); + return new ArrayList<>(getNodeGetDomain().processGetJsonFromNodes(nodes, commitToPass).getActiveElementMap().values()); } @@ -153,16 +147,12 @@ public List findAll(String projectId, String refId, String commitId public void streamAllAtCommit(String projectId, String refId, String commitId, OutputStream stream, String separator) { ContextHolder.setContext(projectId, refId); List nodes; - Optional branch = branchDAO.findByBranchId(refId); - validateBranch(branch); - Optional latestCommit = commitDAO.findLatestByRef(branch.get()); - if (commitId != null && !commitId.isEmpty() && !commitId.equals(latestCommit.map(Commit::getCommitId).orElse(null))) { - validateCommit(commitDAO.findByCommitId(commitId)); + final String commitToPass = checkCommit(refId, commitId); + if (commitToPass != null) { nodes = nodeDAO.findAll(); } else { nodes = nodeDAO.findAllByDeleted(false); } - AtomicInteger counter = new AtomicInteger(); batches(nodes, streamLimit).forEach(ns -> { try { @@ -171,8 +161,9 @@ public void streamAllAtCommit(String projectId, String refId, String commitId, O } else { stream.write(separator.getBytes(StandardCharsets.UTF_8)); } - Collection result = getNodeGetDomain().processGetJsonFromNodes(ns, commitId) + Collection result = getNodeGetDomain().processGetJsonFromNodes(ns, commitToPass) .getActiveElementMap().values(); + result.forEach(v -> v.setRefId(refId)); stream.write(result.stream().map(this::toJson).collect(Collectors.joining(separator)) .getBytes(StandardCharsets.UTF_8)); } catch (IOException ioe) { @@ -187,11 +178,29 @@ public void branchElements(RefJson parentBranch, CommitJson parentCommit, RefJso if (parentBranch != null && parentCommit != null && targetBranch != null) { String projectId = parentBranch.getProjectId(); ContextHolder.setContext(projectId, parentBranch.getId()); + Optional latest = commitPersistence.findLatestByProjectAndRef(projectId, parentBranch.getId()); Set docIds = new HashSet<>(); - for (Node n : nodeDAO.findAllByDeleted(false)) { - docIds.add(n.getDocId()); - } ContextHolder.setContext(projectId, targetBranch.getId()); + if (latest.isPresent() && !latest.get().getId().equals(parentCommit.getId())) { + FederatedNodeGetInfo info = (FederatedNodeGetInfo)getNodeGetDomain().processGetJsonFromNodes(nodeDAO.findAll(), parentCommit.getId()); + for (Node node: info.getExistingNodeMap().values()) { + ElementJson el = info.getActiveElementMap().get(node.getNodeId()); + if (el != null) { + node.setDocId(el.getDocId()); + node.setLastCommit(el.getCommitId()); + docIds.add(el.getDocId()); + node.setDeleted(false); + } else { + node.setDeleted(true); + } + } + nodeDAO.saveAll(info.getExistingNodeMap().values().stream().toList()); + + } else { + for (Node n : nodeDAO.findAllByDeleted(false)) { + docIds.add(n.getDocId()); + } + } nodeIndexDAO.addToRef(docIds); } else { throw new InternalErrorException("Error committing transaction"); @@ -257,4 +266,17 @@ private void validateCommit(Optional commit) { throw new BadRequestException("commit id is invalid"); } } + + // if commitId is latest, return null + private String checkCommit(String refId, String commitId) { + Optional branch = branchDAO.findByBranchId(refId); + validateBranch(branch); + if (commitId != null && !commitId.isEmpty() && !commitId.equals( + commitDAO.findLatestByRef(branch.get()).map(Commit::getCommitId).orElse(null))) { + validateCommit(commitDAO.findByCommitId(commitId)); + return commitId; + } else { + return null; + } + } } diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedOrgPersistence.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedOrgPersistence.java index 0bc7b70bc..c293e6804 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedOrgPersistence.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedOrgPersistence.java @@ -33,10 +33,7 @@ public void setJsonUtils(FederatedJsonUtils jsonUtils) { @Override public OrgJson save(OrgJson orgJson) { Optional organizationOptional = orgDAO.findByOrganizationId(orgJson.getId()); - if (organizationOptional.isPresent()) { - throw new ForbiddenException("org " + orgJson.getId() + " already exists"); - } - Organization organization = new Organization(); + Organization organization = organizationOptional.orElse(new Organization()); organization.setOrganizationId(orgJson.getId()); organization.setOrganizationName(orgJson.getName()); return getOrgJson(orgDAO.save(organization)); diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedProjectPersistence.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedProjectPersistence.java index 116c2fa43..68d545a13 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedProjectPersistence.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/dao/FederatedProjectPersistence.java @@ -82,10 +82,10 @@ public List findAll() { @Transactional public Collection findAllByOrgId(String orgId) { Optional org = orgRepository.findByOrganizationId(orgId); - if(org.isEmpty()) { + if (org.isEmpty()) { throw new NotFoundException("org not found"); } - if(org.get().getProjects() == null) { + if (org.get().getProjects() == null) { return List.of(); } return org.get().getProjects().stream().map(project -> { @@ -100,21 +100,17 @@ public void hardDelete(String projectId) { try { ContextHolder.clearContext(); projectDAO.delete(projectId); - } catch (Exception ex){ - message = message.concat("Project DAO, cannot delete. "); + } catch (Exception e) { + message.concat(e.getMessage()); } try { ContextHolder.setContext(projectId); projectIndexDAO.delete(projectId); - if(!message.isEmpty()) { - message = message.concat("Project index DAO deleted "); - } - } catch (Exception ex){ - message = message.concat("Project index DAO, cannot delete. "); + } catch (Exception e) { + message.concat(e.getMessage()); } - - if(!message.isEmpty()) { - throw new NotFoundException(message); + if (!message.isEmpty()) { + throw new InternalErrorException(message); } } diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeChangeDomain.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeChangeDomain.java index be39d90ee..1d4ecc866 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeChangeDomain.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeChangeDomain.java @@ -1,7 +1,9 @@ package org.openmbee.mms.federatedpersistence.domain; import org.openmbee.mms.core.config.Constants; +import org.openmbee.mms.core.config.Formats; import org.openmbee.mms.crud.domain.NodeUpdateFilter; +import org.openmbee.mms.data.dao.CommitDAO; import org.openmbee.mms.data.dao.NodeDAO; import org.openmbee.mms.data.dao.NodeIndexDAO; import org.openmbee.mms.core.exceptions.InternalErrorException; @@ -9,7 +11,7 @@ import org.openmbee.mms.core.services.NodeChangeInfo; import org.openmbee.mms.crud.domain.CommitDomain; import org.openmbee.mms.crud.domain.NodeChangeDomain; -import org.openmbee.mms.crud.domain.NodeGetDomain; +import org.openmbee.mms.data.domains.scoped.Commit; import org.openmbee.mms.data.domains.scoped.Node; import org.openmbee.mms.federatedpersistence.dao.FederatedNodeChangeInfo; import org.openmbee.mms.federatedpersistence.dao.FederatedNodeChangeInfoImpl; @@ -34,16 +36,18 @@ public class FederatedNodeChangeDomain extends NodeChangeDomain { protected FederatedElementDomain elementDomain; protected NodeDAO nodeRepository; protected NodeIndexDAO nodeIndex; + protected CommitDAO commitDAO; @Autowired - public FederatedNodeChangeDomain(NodeGetDomain nodeGetDomain, CommitDomain commitDomain, + public FederatedNodeChangeDomain(CommitDomain commitDomain, FederatedNodeGetDomain getDomain, NodeDAO nodeRepository, NodeIndexDAO nodeIndex, FederatedElementDomain elementDomain, - List nodeUpdateFilters) { - super(nodeGetDomain, commitDomain, nodeUpdateFilters); + List nodeUpdateFilters, CommitDAO commitDAO) { + super(getDomain, commitDomain, nodeUpdateFilters); this.getDomain = getDomain; this.nodeRepository = nodeRepository; this.nodeIndex = nodeIndex; this.elementDomain = elementDomain; + this.commitDAO = commitDAO; } @Override @@ -54,14 +58,14 @@ protected NodeChangeInfo createNodeChangeInfo() { @Override public NodeChangeInfo initInfo(CommitJson commitJson, boolean overwrite, boolean preserveTimestamps) { commitJson.setId(UUID.randomUUID().toString()); - commitJson.setDocId(commitJson.getId()); + commitJson.setDocId(commitJson.getId()); NodeChangeInfo info = super.initInfo(commitJson, overwrite, preserveTimestamps); if(info instanceof FederatedNodeChangeInfo) { ((FederatedNodeChangeInfo)info).setOldDocIds(new HashSet<>()); ((FederatedNodeChangeInfo)info).setReqIndexIds(new HashSet<>()); ((FederatedNodeChangeInfo)info).setToSaveNodeMap(new HashMap<>()); - } else { + } else { throw new InternalErrorException("Unexpected NodeChangeInfo type in FederatedNodeChangeDomain"); } return info; @@ -80,7 +84,7 @@ public void processElementAdded(NodeChangeInfo info, ElementJson element) { ((FederatedNodeChangeInfo) info).getExistingNodeMap().put(element.getId(), node); super.processElementAdded(info, element); - node.setInitialCommit(element.getDocId()); + node.setInitialCommit(element.getCommitId()); CommitJson commitJson = info.getCommitJson(); ElementVersion newObj = new ElementVersion() @@ -93,7 +97,7 @@ public void processElementAdded(NodeChangeInfo info, ElementJson element) { } @Override - public void processElementUpdated(NodeChangeInfo info, ElementJson element, ElementJson existing) { + public boolean processElementUpdated(NodeChangeInfo info, ElementJson element, ElementJson existing) { if(!(info instanceof FederatedNodeChangeInfo)) { throw new InternalErrorException("Unexpected NodeChangeInfo type in FederatedNodeChangeDomain"); } @@ -106,16 +110,19 @@ public void processElementUpdated(NodeChangeInfo info, ElementJson element, Elem existing.setIsDeleted(Constants.TRUE); } } else { - return; + return false; } - super.processElementUpdated(info, element, existing); + if (!super.processElementUpdated(info, element, existing)) { + return false; + } ElementVersion newObj= new ElementVersion() .setPreviousDocId(previousDocId) .setDocId(element.getDocId()) .setId(element.getId()) .setType("Element"); info.getCommitJson().getUpdated().add(newObj); + return true; } @Override @@ -133,7 +140,7 @@ protected void processElementAddedOrUpdated(NodeChangeInfo info, ElementJson ele String docId = UUID.randomUUID().toString(); element.setDocId(docId); - super.processElementAddedOrUpdated(info, element); + super.processElementAddedOrUpdated(info, element); n.setDocId(element.getDocId()); n.setLastCommit(info.getCommitJson().getId()); n.setDeleted(false); @@ -148,10 +155,7 @@ public void processElementDeleted(NodeChangeInfo info, ElementJson element) { throw new InternalErrorException("Unexpected NodeChangeInfo type in FederatedNodeChangeDomain"); } Node n = ((FederatedNodeChangeInfo) info).getExistingNodeMap().get(element.getId()); - if(n != null) { - n.setNodeId(element.getId()); - n.setInitialCommit(element.getDocId()); - } else { + if (n == null) { return; } @@ -183,9 +187,14 @@ public FederatedNodeChangeInfo processDeleteJson(NodeChangeInfo info, Collection ElementJson indexElement = info.getExistingElementMap().get(nodeId); if (node.isDeleted()) { - info.addRejection(nodeId, new Rejection(indexElement, 410, "Already deleted")); + info.addRejection(nodeId, new Rejection(indexElement, 410, "Already deleted")); continue; } + if (indexElement == null) { + logger.warn("node db and index mismatch on element delete: nodeId: " + nodeId + + ", docId not found: " + federatedInfo.getExistingNodeMap().get(nodeId).getDocId()); + indexElement = new ElementJson().setId(nodeId).setDocId(node.getDocId()); + } ElementJson request = info.getReqElementMap().get(nodeId); request.putAll(indexElement); @@ -227,8 +236,12 @@ public FederatedNodeChangeInfo processPostJson(NodeChangeInfo info, Collection init = commitDAO.findByCommitId(n.getInitialCommit()); + if (init.isPresent()) { + indexElement.setCreator(init.get().getCreator()); + indexElement.setCreated(Formats.FORMATTER.format(init.get().getTimestamp())); + } } // create new doc id for all element json, update modified time, modifier (use dummy for now), set _projectId, _refId, _inRefIds @@ -241,41 +254,42 @@ public FederatedNodeChangeInfo processPostJson(NodeChangeInfo info, Collection existingElements) { - getDomain.addExistingElements(nodeChangeInfo, existingElements); - } - //ToDo :: Check @Override public void primeNodeChangeInfo(NodeChangeInfo nodeChangeInfo, Collection transactedElements) { Set elementIds = transactedElements.stream().map(BaseJson::getId).filter(id->null!=id).collect(Collectors.toSet()); List existingNodes = nodeRepository.findAllByNodeIds(elementIds); - Set indexIds = new HashSet<>(); - Map existingNodeMap = new HashMap<>(); - Map reqElementMap = new HashMap<>(); + if (!(nodeChangeInfo instanceof FederatedNodeChangeInfo)) { + throw new InternalErrorException("Node processing is not using FederatedNodeChangeInfo"); + } + + FederatedNodeChangeInfo info = (FederatedNodeChangeInfo)nodeChangeInfo; + Set indexIds = Optional.ofNullable(info.getReqIndexIds()).orElse(new HashSet<>()); + Map existingNodeMap = Optional.ofNullable(info.getExistingNodeMap()).orElse(new HashMap<>()); + Map reqElementMap = new HashMap<>(); // don't add to any existing since this change processing is only for transactedElements + Map existingElementMap = Optional.ofNullable(info.getExistingElementMap()).orElse(new HashMap<>()); + + Set transactedIndexIds = new HashSet<>(); for (Node node : existingNodes) { + transactedIndexIds.add(node.getDocId()); indexIds.add(node.getDocId()); existingNodeMap.put(node.getNodeId(), node); - // reqElementMap.put(node.getNodeId(), new ElementJson().setId(node.getNodeId())); } - if(!transactedElements.isEmpty()){ - reqElementMap.putAll(convertJsonToMap(transactedElements.parallelStream().collect(Collectors.toList()))); + if (!transactedElements.isEmpty()) { + reqElementMap.putAll(convertJsonToMap(transactedElements)); } // bulk read existing elements in elastic - List existingElements = nodeIndex.findAllById(indexIds); - Map existingElementMap = convertJsonToMap(existingElements); - - if (nodeChangeInfo instanceof FederatedNodeChangeInfo) { - ((FederatedNodeChangeInfo) nodeChangeInfo).setExistingElementMap(existingElementMap); - ((FederatedNodeChangeInfo) nodeChangeInfo).setExistingNodeMap(existingNodeMap); - ((FederatedNodeChangeInfo) nodeChangeInfo).setReqElementMap(reqElementMap); - ((FederatedNodeChangeInfo) nodeChangeInfo).setReqIndexIds(indexIds); - ((FederatedNodeChangeInfo) nodeChangeInfo).setRejected(new HashMap<>()); - ((FederatedNodeChangeInfo) nodeChangeInfo).setActiveElementMap(new HashMap<>()); - } + List existingElements = nodeIndex.findAllById(transactedIndexIds); + existingElementMap.putAll(convertJsonToMap(existingElements)); + + info.setExistingElementMap(existingElementMap); + info.setReqElementMap(reqElementMap); + info.setRejected(Optional.ofNullable(info.getRejected()).orElse(new HashMap<>())); + info.setActiveElementMap(Optional.ofNullable(info.getActiveElementMap()).orElse(new HashMap<>())); + info.setExistingNodeMap(existingNodeMap); + info.setReqIndexIds(indexIds); } } diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeGetDomain.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeGetDomain.java index c88c9ba49..36489e1d3 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeGetDomain.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/domain/FederatedNodeGetDomain.java @@ -2,18 +2,20 @@ import org.openmbee.mms.core.config.ContextHolder; import org.openmbee.mms.core.config.Formats; -import org.openmbee.mms.core.dao.CommitPersistence; -import org.openmbee.mms.data.dao.NodeDAO; -import org.openmbee.mms.data.dao.NodeIndexDAO; +import org.openmbee.mms.data.dao.*; import org.openmbee.mms.core.exceptions.BadRequestException; import org.openmbee.mms.core.exceptions.InternalErrorException; import org.openmbee.mms.core.services.NodeGetInfo; import org.openmbee.mms.crud.domain.NodeGetDomain; +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.federatedpersistence.dao.FederatedNodeGetInfo; import org.openmbee.mms.federatedpersistence.dao.FederatedNodeGetInfoImpl; import org.openmbee.mms.json.CommitJson; import org.openmbee.mms.json.ElementJson; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -26,15 +28,22 @@ @Component public class FederatedNodeGetDomain extends NodeGetDomain { - private CommitPersistence commitPersistence; + protected static final Logger logger = LoggerFactory.getLogger(FederatedNodeGetDomain.class); + private NodeDAO nodeDAO; private NodeIndexDAO nodeIndex; + private CommitDAO commitDAO; + private BranchDAO branchDAO; + private CommitIndexDAO commitIndex; @Autowired - public FederatedNodeGetDomain(CommitPersistence commitPersistence, NodeDAO nodeDAO, NodeIndexDAO nodeIndex) { - this.commitPersistence = commitPersistence; + public FederatedNodeGetDomain(NodeDAO nodeDAO, NodeIndexDAO nodeIndex, + CommitDAO commitDAO, BranchDAO branchDAO, CommitIndexDAO commitIndex) { this.nodeDAO = nodeDAO; this.nodeIndex = nodeIndex; + this.commitDAO = commitDAO; + this.branchDAO = branchDAO; + this.commitIndex = commitIndex; } public NodeGetInfo initInfo(List elements, CommitJson commitJson) { @@ -44,12 +53,22 @@ public NodeGetInfo initInfo(List elements, CommitJson commitJson) { NodeGetInfo nodeGetInfo = initInfoFromNodes(existingNodes, commitJson); nodeGetInfo.getReqElementMap().putAll(convertJsonToMap(elements)); return nodeGetInfo; - + } public NodeGetInfo initInfoFromNodes(List existingNodes, CommitJson commitJson) { NodeGetInfo nodeGetInfo = super.initInfo(commitJson, this::createNodeGetInfo); Set indexIds = existingNodes.stream().map(Node::getDocId).collect(Collectors.toSet()); + if (nodeGetInfo instanceof FederatedNodeGetInfo) { + FederatedNodeGetInfo federatedInfo = (FederatedNodeGetInfo)nodeGetInfo; + federatedInfo.setExistingNodeMap(new HashMap<>()); + federatedInfo.setReqIndexIds(new HashSet<>()); + for (Node node : existingNodes) { + federatedInfo.getReqIndexIds().add(node.getDocId()); + federatedInfo.getExistingNodeMap().put(node.getNodeId(), node); + federatedInfo.getReqElementMap().put(node.getNodeId(), new ElementJson().setId(node.getNodeId())); + } + } // bulk read existing elements in elastic List existingElements = nodeIndex.findAllById(indexIds); addExistingElements(nodeGetInfo, existingElements); // handeled in addExistingElements @@ -93,7 +112,12 @@ protected NodeGetInfo processLatest(NodeGetInfo info) { continue; } ElementJson indexElement = info.getExistingElementMap().get(nodeId); - + if (indexElement == null) { + logger.warn("node db and index mismatch on element get: nodeId: " + nodeId + + ", docId not found: " + federatedInfo.getExistingNodeMap().get(nodeId).getDocId()); + rejectNotFound(info, nodeId); + continue; + } if (federatedInfo.getExistingNodeMap().get(nodeId).isDeleted()) { rejectDeleted(info, nodeId, indexElement); continue; @@ -104,22 +128,40 @@ protected NodeGetInfo processLatest(NodeGetInfo info) { } protected NodeGetInfo processCommit(NodeGetInfo info, String commitId) { - if(!(info instanceof FederatedNodeGetInfo)) { + if (!(info instanceof FederatedNodeGetInfo)) { throw new InternalErrorException("Invalid use of FederatedNodeGetDomain"); } FederatedNodeGetInfo federatedInfo = (FederatedNodeGetInfo) info; - Optional commit = commitPersistence.findById(getContext().getProjectId(), commitId); + Optional commit = commitDAO.findByCommitId(commitId); if (!commit.isPresent() ) { throw new BadRequestException("commitId is invalid"); } - Instant time = Instant.from(Formats.FORMATTER.parse(commit.get().getCreated())); //time of commit + Instant time = commit.get().getTimestamp(); //time of commit List refCommitIds = null; //get it later if needed for (String nodeId : info.getReqElementMap().keySet()) { if (!existingNodeContainsNodeId(federatedInfo, nodeId)) { // nodeId not found continue; } ElementJson indexElement = info.getExistingElementMap().get(nodeId); - if(info.getCommitJson() != null && info.getCommitJson().getRefId() != null) { + if (indexElement == null) { + // latest element not found, mock an object to continue + Node n = federatedInfo.getExistingNodeMap().get(nodeId); + logger.warn("node db and index mismatch on element commit get: nodeId: " + nodeId + + ", docId not found: " + n.getDocId()); + Optional last = commitDAO.findByCommitId(n.getLastCommit()); + Optional first = commitDAO.findByCommitId(n.getInitialCommit()); + if (!last.isPresent() || !first.isPresent()) { + rejectNotFound(info, nodeId); + continue; + } + indexElement = new ElementJson().setId(nodeId).setDocId(n.getDocId()); + indexElement.setModified(Formats.FORMATTER.format(last.get().getTimestamp())); + indexElement.setModifier(last.get().getCreator()); + indexElement.setCommitId(last.get().getCommitId()); + indexElement.setCreator(first.get().getCreator()); + indexElement.setCreated(Formats.FORMATTER.format(first.get().getTimestamp())); + } + if (info.getCommitJson() != null && info.getCommitJson().getRefId() != null) { indexElement.setRefId(info.getCommitJson().getRefId()); } else { indexElement.setRefId(ContextHolder.getContext().getBranchId()); @@ -144,13 +186,24 @@ protected NodeGetInfo processCommit(NodeGetInfo info, String commitId) { Optional e = nodeIndex.getElementLessThanOrEqualTimestamp(nodeId, Formats.FORMATTER.format(time), refCommitIds); if (e.isPresent()) { // found version of element at commit time - //TODO determine if element was deleted at the time? - addActiveElement(info, nodeId, e.get()); + Instant realModified = Instant.from(Formats.FORMATTER.parse(e.get().getModified())); + if (elementDeleted(nodeId, commitId, time, realModified, refCommitIds)) { + rejectDeleted(info, nodeId, e.get()); + } else { + addActiveElement(info, nodeId, e.get()); + } } else { rejectNotFound(info, nodeId); // element not found at commit time } } else if (federatedInfo.getExistingNodeMap().get(nodeId).isDeleted()) { // latest element is before commit, but deleted - rejectDeleted(info, nodeId, indexElement); + if (refCommitIds == null) { // need list of commitIds of current ref to filter on + refCommitIds = getRefCommitIds(time); + } + if (elementDeleted(nodeId, commitId, time, modified, refCommitIds)) { + rejectDeleted(info, nodeId, indexElement); + } else { + addActiveElement(info, nodeId, indexElement); + } } else { // latest element version is version at commit, not deleted addActiveElement(info, nodeId, indexElement); } @@ -158,6 +211,19 @@ protected NodeGetInfo processCommit(NodeGetInfo info, String commitId) { return info; } + private boolean elementDeleted(String nodeId, String commitId, Instant time, Instant modified, List refCommitIds) { + List commits = commitIndex.elementDeletedHistory(nodeId, refCommitIds); + for (CommitJson c: commits) { + Instant deletedTime = Instant.from(Formats.FORMATTER.parse(c.getCreated())); + if ((deletedTime.isBefore(time) || c.getId().equals(commitId)) && deletedTime.isAfter(modified)) { + //there's a delete between element last modified time and requested commit time + //or element is deleted at commit + return true; + } + } + return false; + } + public boolean existingNodeContainsNodeId(FederatedNodeGetInfo info, String nodeId) { if (!info.getExistingNodeMap().containsKey(nodeId)) { rejectNotFound(info, nodeId); @@ -173,34 +239,23 @@ protected void addActiveElement(NodeGetInfo info, String nodeId, ElementJson ind protected List getRefCommitIds(Instant time) { List commitIds = new ArrayList<>(); - List refCommits = commitPersistence.findByProjectAndRefAndTimestampAndLimit(getContext().getProjectId(), getContext().getBranchId(), time, 0); - for (CommitJson c : refCommits) { - commitIds.add(c.getId()); - } + Optional ref = branchDAO.findByBranchId(getContext().getBranchId()); + ref.ifPresent(current -> { + List refCommits = commitDAO.findByRefAndTimestampAndLimit(current, time, 0); + for (Commit c : refCommits) { + commitIds.add(c.getCommitId()); + } + }); return commitIds; } @Override public void addExistingElements(NodeGetInfo info, List elements) { super.addExistingElements(info, elements); - - if(info instanceof FederatedNodeGetInfo) { - FederatedNodeGetInfo federatedInfo = (FederatedNodeGetInfo)info; - Set elementIds = elements.stream().map(ElementJson::getId).collect(Collectors.toSet()); - List existingNodes = nodeDAO.findAllByNodeIds(elementIds); - //ToDo : could also be done in get functions in respective classes to prevent extra null checks and NPE - federatedInfo.setExistingNodeMap(new HashMap<>()); - federatedInfo.setReqIndexIds(new HashSet<>()); - for (Node node : existingNodes) { - federatedInfo.getReqIndexIds().add(node.getDocId()); - federatedInfo.getExistingNodeMap().put(node.getNodeId(), node); - federatedInfo.getReqElementMap().put(node.getNodeId(), new ElementJson().setId(node.getNodeId())); - } - } } @Override - public NodeGetInfo createNodeGetInfo() { //ToDo :: check + public NodeGetInfo createNodeGetInfo() { //ToDo :: check return new FederatedNodeGetInfoImpl(); } } diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/AbstractDefaultPermissionsDelegate.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/AbstractDefaultPermissionsDelegate.java index 6f36ecfd8..f3086980a 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/AbstractDefaultPermissionsDelegate.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/AbstractDefaultPermissionsDelegate.java @@ -64,7 +64,8 @@ protected Pair getGroupAndRole(PermissionUpdateRequest.Permission p } if (!group.isPresent()) { group = Optional.of(new Group(p.getName())); - getGroupRepo().save(group.get()); + Group g = getGroupRepo().save(group.get()); + group = Optional.of(g); } return Pair.of(group.get(), role.get()); } diff --git a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/FederatedPermissionUpdatesResponseBuilder.java b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/FederatedPermissionUpdatesResponseBuilder.java index 03cd7271b..9922c4e77 100644 --- a/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/FederatedPermissionUpdatesResponseBuilder.java +++ b/federatedpersistence/src/main/java/org/openmbee/mms/federatedpersistence/permissions/FederatedPermissionUpdatesResponseBuilder.java @@ -6,31 +6,9 @@ public class FederatedPermissionUpdatesResponseBuilder extends PermissionUpdatesResponseBuilder { - private Boolean inherit; - private Boolean isPublic; private FederatedPermissionsUpdateResponseBuilder usersBuilder = new FederatedPermissionsUpdateResponseBuilder(); private FederatedPermissionsUpdateResponseBuilder groupsBuilder = new FederatedPermissionsUpdateResponseBuilder(); - @Override - public FederatedPermissionUpdatesResponseBuilder setInherit(Boolean inherit) { - this.inherit = inherit; - return this; - } - - @Override - public FederatedPermissionUpdatesResponseBuilder setPublic(Boolean aPublic) { - isPublic = aPublic; - return this; - } - - @Override - public FederatedPermissionUpdatesResponseBuilder insert(PermissionUpdatesResponse permissionUpdatesResponse) { - this.inherit = or(this.inherit, permissionUpdatesResponse.getInherit()); - this.isPublic = or(this.isPublic, permissionUpdatesResponse.getPublic()); - this.insertUsers(permissionUpdatesResponse.getUsers()); - this.insertGroups(permissionUpdatesResponse.getGroups()); - return this; - } @Override public FederatedPermissionUpdatesResponseBuilder insertUsers(PermissionUpdateResponse permissionUpdateResponse) { @@ -64,13 +42,4 @@ public FederatedPermissionsUpdateResponseBuilder getGroups() { return groupsBuilder; } - private Boolean or(Boolean a, Boolean b) { - if (a == null) { - return b; - } - if (a.equals(b)) { - return a; - } - return a || b; - } } diff --git a/gradle.properties b/gradle.properties index 3a9c13be2..8d975667a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,11 +1,12 @@ -version=4.0.19 +version=4.0.20 group=org.openmbee.mms -springBootVersion=2.7.17 -springFrameworkVersion=5.3.30 -springSecurityVersion=5.7.10 -springDataVersion=2.7.14 -jacksonVersion=2.13.3 +springBootVersion=2.7.18 +springFrameworkVersion=5.3.31 +springSecurityVersion=5.7.11 +springDataVersion=2.7.18 +jacksonVersion=2.16.1 +jacksonBomVersion=2.16.1 elasticVersion=7.8.1 jwtTokenVersion=0.10.5 diff --git a/json/src/main/java/org/openmbee/mms/json/BaseJson.java b/json/src/main/java/org/openmbee/mms/json/BaseJson.java index 0d628e022..b99b8b8e7 100644 --- a/json/src/main/java/org/openmbee/mms/json/BaseJson.java +++ b/json/src/main/java/org/openmbee/mms/json/BaseJson.java @@ -22,7 +22,7 @@ public class BaseJson extends HashMap { public static final String CREATED = "_created"; public static final String COMMITID = "_commitId"; public static final String TYPE = "type"; - public static final String IS_DELETED = "deleted"; + public static final String IS_DELETED = "_deleted"; public String getId() { return (String) this.get(ID); diff --git a/jupyter/src/main/java/org/openmbee/mms/jupyter/services/JupyterNodeService.java b/jupyter/src/main/java/org/openmbee/mms/jupyter/services/JupyterNodeService.java index 96e57b6f2..cfcc1ed8f 100644 --- a/jupyter/src/main/java/org/openmbee/mms/jupyter/services/JupyterNodeService.java +++ b/jupyter/src/main/java/org/openmbee/mms/jupyter/services/JupyterNodeService.java @@ -9,6 +9,7 @@ import org.openmbee.mms.core.objects.ElementsResponse; import org.openmbee.mms.core.objects.Rejection; import org.openmbee.mms.core.services.NodeChangeInfo; +import org.openmbee.mms.crud.domain.JsonDomain; import org.openmbee.mms.json.ElementJson; import org.openmbee.mms.crud.services.DefaultNodeService; import org.openmbee.mms.core.services.NodeService; @@ -59,7 +60,7 @@ public ElementsResponse readNotebooks(String projectId, String refId, ElementsRe ElementsRequest req2 = new ElementsRequest(); req2.setElements(req2s); ElementsResponse cells = this.read(projectId, refId, req2, params); - Map cellmap = convertJsonToMap(cells.getElements()); + Map cellmap = JsonDomain.convertJsonToMap(cells.getElements()); e.put(JupyterConstants.CELLS, order((List)e.get(JupyterConstants.CELLS), cellmap)); } res.getElements().removeAll(nonNotebooks); diff --git a/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java b/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java index 5dfcba1cc..858ea4a1f 100644 --- a/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java +++ b/localuser/src/main/java/org/openmbee/mms/localuser/controllers/LocalUserController.java @@ -48,7 +48,7 @@ public UserCreateRequest createUser(@RequestBody UserCreateRequest req) { } @GetMapping(value = "/users") - @PreAuthorize(AuthorizationConstants.IS_MMSADMIN) + @PreAuthorize("isAuthenticated()") public UsersResponse getUsers(@RequestParam(required = false) String user) { UsersResponse res = new UsersResponse(); Collection users = new ArrayList<>(); diff --git a/msosa/src/main/java/org/openmbee/mms/msosa/services/MsosaViewService.java b/msosa/src/main/java/org/openmbee/mms/msosa/services/MsosaViewService.java index 55f7c0f83..cf1e7a4da 100644 --- a/msosa/src/main/java/org/openmbee/mms/msosa/services/MsosaViewService.java +++ b/msosa/src/main/java/org/openmbee/mms/msosa/services/MsosaViewService.java @@ -11,6 +11,7 @@ import java.util.Set; import java.util.UUID; +import org.openmbee.mms.crud.domain.JsonDomain; import org.openmbee.mms.msosa.MsosaConstants; import org.openmbee.mms.msosa.MsosaNodeType; import org.openmbee.mms.core.config.ContextHolder; @@ -60,7 +61,7 @@ public void addChildViews(ElementsResponse res, Map params) { List ownedAttributeIds = (List) element.get(MsosaConstants.OWNEDATTRIBUTEIDS); ElementsResponse ownedAttributes = this.read(element.getProjectId(), element.getRefId(), buildRequest(ownedAttributeIds), params); - List filtered = filter(ownedAttributeIds, ownedAttributes.getElements()); + List filtered = JsonDomain.filter(ownedAttributeIds, ownedAttributes.getElements()); List childViews = new ArrayList<>(); for (ElementJson attr : filtered) { String childId = (String) attr.get(MsosaConstants.TYPEID); @@ -153,7 +154,7 @@ public void extraProcessPostedElement(NodeChangeInfo info, ElementJson element) //existing property and type, reuse PropertyData data = oldPropertiesTypeMapping.get(typeId); newProperties.add(data); - newAttributeIds.add(data.getPropertyJson().getId()); + newAttributeIds.add(data.getPropertyJson().getId()); continue; } //create new properties and association diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectDAOImpl.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectDAOImpl.java index 6aec4672e..0d7405a0f 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectDAOImpl.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/ProjectDAOImpl.java @@ -65,13 +65,15 @@ public void delete(String projectId) { try { projectRepository.findByProjectId(projectId).ifPresent(v -> projectRepository.delete(v)); } catch (Exception ex) { - logger.error("Could not delete project from project Repository"); + logger.error("Could not delete project from project Repository", ex); + throw new InternalErrorException(ex); } try { projectOperations.deleteProjectDatabase(projectId); } catch (SQLException ex) { - logger.error("DELETE PROJECT DATABASE EXCEPTION\nPotential connection issue, query statement mishap, or unexpected RDB behavior."); + logger.error("DELETE PROJECT DATABASE EXCEPTION\nPotential connection issue, query statement mishap, or unexpected RDB behavior.", ex); + throw new InternalErrorException(ex); } } diff --git a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/branch/BranchDAOImpl.java b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/branch/BranchDAOImpl.java index bb236cc1c..360788db7 100644 --- a/rdb/src/main/java/org/openmbee/mms/rdb/repositories/branch/BranchDAOImpl.java +++ b/rdb/src/main/java/org/openmbee/mms/rdb/repositories/branch/BranchDAOImpl.java @@ -37,7 +37,7 @@ public Branch save(Branch branch) { if (branch.getId() == null) { ContextHolder.setContext(ContextHolder.getContext().getProjectId(), branch.getBranchId()); - if(!Constants.MASTER_BRANCH.equals(branch.getBranchId())) { + if (!Constants.MASTER_BRANCH.equals(branch.getBranchId())) { branchesOperations.createBranch(); branchesOperations.copyTablesFromParent(branch.getBranchId(), branch.getParentRefId(), null); } @@ -56,7 +56,6 @@ public PreparedStatement createPreparedStatement(Connection connection) } else { throw new NotFoundException("Key value was null"); } - } else { getConn().update(new PreparedStatementCreator() { public PreparedStatement createPreparedStatement(Connection connection) diff --git a/sonar-project.properties b/sonar-project.properties index b3bfa8103..581029b1d 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,3 +2,4 @@ sonar.projectKey=Open-MBEE_exec-mms sonar.organization=openmbee sonar.language=java sonar.java.binaries=**/build/classes/java/main +sonar.coverage.jacoco.xmlReportPaths=jacocoOutput/jacocoXMLReport \ No newline at end of file diff --git a/storage/storage.gradle b/storage/storage.gradle index 3fc3b6db7..d4aac202c 100644 --- a/storage/storage.gradle +++ b/storage/storage.gradle @@ -1,8 +1,8 @@ dependencies { api project(':artifacts') - implementation 'com.amazonaws:aws-java-sdk-s3:1.11.874' - implementation 'org.apache.tika:tika-parsers:1.24.1' + implementation 'com.amazonaws:aws-java-sdk-s3:1.12.638' + implementation 'org.apache.tika:tika-core:2.9.1' implementation commonDependencies.'servlet-api' testImplementation commonDependencies.'spring-boot-starter-test' diff --git a/view/src/main/java/org/openmbee/mms/view/controllers/VeController.java b/view/src/main/java/org/openmbee/mms/view/controllers/VeController.java index 480e336cb..6e54ae507 100644 --- a/view/src/main/java/org/openmbee/mms/view/controllers/VeController.java +++ b/view/src/main/java/org/openmbee/mms/view/controllers/VeController.java @@ -99,14 +99,6 @@ public ElementsResponse createOrUpdateViews( ViewService viewService = genericServiceFactory.getServiceForSchema( ViewService.class , getProjectType(projectId)); ElementsResponse res = viewService.createOrUpdate(projectId, refId, req, params, auth.getName()); - // ToDo : the following is just a workaround till the indexing part is synchronized W - try { - Thread.sleep(1000); // Providing some delay for the indexing to complete as it uses async api call - } catch(InterruptedException e) { - Thread.currentThread().interrupt(); - } catch (Exception e) { - // No need to handle this...... - } viewService.addChildViews(res, params); return res; }