Skip to content

Commit

Permalink
Merge pull request #27 from who-icatx/18-getchildren-should-return-er…
Browse files Browse the repository at this point in the history
…ror-if-iri-in-request-does-not-exists

Added validation on get-entity-children
  • Loading branch information
soimugeoWB authored Jan 7, 2025
2 parents e303cf6 + 6b9adf7 commit c2add51
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 96 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Verify

on:
push:
branches-ignore:
- master

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
- name: Build with Maven
run: mvn --batch-mode package
55 changes: 55 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Release

on:
push:
branches:
- master

jobs:
build:
runs-on: ubuntu-latest
if: ${{ github.actor != 'who-icatx-bot[bot]' }}
steps:
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{secrets.DOCKER_USERNAME}}
password: ${{secrets.DOCKER_PASSWORD}}
- uses: actions/create-github-app-token@v1
id: app-token
with:
app-id: ${{ vars.ICATX_BOT_APP_ID }}
private-key: ${{ secrets.ICATX_BOT_APP_PRIVATE_KEY }}
- uses: actions/checkout@v4
with:
token: ${{ steps.app-token.outputs.token }}
ref: ${{ github.head_ref }}
- name: Set up Maven Central Repository
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'adopt'
server-id: docker.io
server-username: DOCKER_USERNAME
server-password: DOCKER_PASSWORD
- name: Bump version
id: bump
uses: mickem/gh-action-bump-maven-version@v1
- name: Build package
run: mvn --batch-mode clean package
- name: Build and push image
run: mvn --batch-mode package install
- name: Release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.bump.outputs.tag }}
generate_release_notes: true

env:
DOCKER_USERNAME: ${{secrets.DOCKER_USERNAME}}
DOCKER_TOKEN: ${{secrets.DOCKER_PASSWORD}}

permissions:
contents: write
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</parent>
<groupId>edu.stanford.protege</groupId>
<artifactId>icatx-api-gateway</artifactId>
<version>0.0.2</version>
<version>0.0.3</version>
<name>icatx-api-gateway</name>
<description>This microservice is the api gateway for the iCAT-X project.</description>
<url/>
Expand Down
13 changes: 5 additions & 8 deletions src/main/java/edu/stanford/protege/gateway/OwlEntityService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,17 @@
import edu.stanford.protege.webprotege.common.ProjectId;
import edu.stanford.protege.webprotege.ipc.EventDispatcher;
import edu.stanford.protege.webprotege.ipc.ExecutionContext;
import edu.stanford.protege.webprotege.ipc.ExecutionContext;
import org.slf4j.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Nonnull;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;


@Service
Expand Down Expand Up @@ -113,7 +110,7 @@ public String createClassEntity(String projectId, CreateEntityDto createEntityDt
CompletableFuture<String> newCreatedEntityIri = ontologyService.createClassEntity(projectId, createEntityDto);
try {
return newCreatedEntityIri.get();
} catch (Exception e) {
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("Error creating new class entity " + createEntityDto.title(), e);
/*
ToDo:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.google.common.hash.Hashing;
import edu.stanford.protege.gateway.OwlEntityService;
import edu.stanford.protege.gateway.dto.*;
import edu.stanford.protege.gateway.ontology.validators.CreateEntityValidatorService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
Expand All @@ -24,11 +23,9 @@
public class ProjectsController {

private final OwlEntityService owlEntityService;
private final CreateEntityValidatorService createEntityValidator;

public ProjectsController(OwlEntityService owlEntityService, CreateEntityValidatorService createEntityValidator) {
public ProjectsController(OwlEntityService owlEntityService) {
this.owlEntityService = owlEntityService;
this.createEntityValidator = createEntityValidator;
}


Expand Down Expand Up @@ -63,7 +60,6 @@ public ResponseEntity<OWLEntityDto> createEntity(@PathVariable("projectId")
@NotNull(message = "Project ID cannot be null")
String projectId,
@RequestBody CreateEntityDto createEntityDto) {
createEntityValidator.validateCreateEntityRequest(projectId, createEntityDto);
var newCreatedIri = owlEntityService.createClassEntity(projectId, createEntityDto);
OWLEntityDto result = owlEntityService.getEntityInfo(newCreatedIri, projectId);
return getOwlEntityDtoResponseEntity(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
import org.springframework.stereotype.Service;
import uk.ac.manchester.cs.owl.owlapi.OWLClassImpl;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Service
Expand Down Expand Up @@ -162,6 +164,8 @@ public void updateLanguageTerms(String entityIri, String projectId, String formI
}

public CompletableFuture<List<String>> getEntityChildren(String entityIri, String projectId) {
validateProjectId(projectId);
validateEntityExists(projectId, entityIri);
return entityChildrenExecutor.execute(GetEntityChildrenRequest.create(IRI.create(entityIri), ProjectId.valueOf(projectId)), SecurityContextHelper.getExecutionContext())
.thenApply(
response -> response.childrenIris()
Expand All @@ -176,9 +180,9 @@ public CompletableFuture<Boolean> isExistingProject(String projectId) {
.thenApply(GetIsExistingProjectResponse::isExistingProject);
}

public CompletableFuture<Set<String>> getExistingEntities(String projectId, String parent) {
var parentIri = IRI.create(parent);
return filterExistingEntitiesExecutor.execute(FilterExistingEntitiesRequest.create(ProjectId.valueOf(projectId), ImmutableSet.of(parentIri)), SecurityContextHelper.getExecutionContext())
public CompletableFuture<Set<String>> getExistingEntities(String projectId, String entity) {
var entityIri = IRI.create(entity);
return filterExistingEntitiesExecutor.execute(FilterExistingEntitiesRequest.create(ProjectId.valueOf(projectId), ImmutableSet.of(entityIri)), SecurityContextHelper.getExecutionContext())
.thenApply(
response -> response.existingEntities()
.stream()
Expand All @@ -188,6 +192,7 @@ public CompletableFuture<Set<String>> getExistingEntities(String projectId, Stri
}

public CompletableFuture<String> createClassEntity(String projectId, CreateEntityDto createEntityDto) {
validateCreateEntityRequest(projectId, createEntityDto);
return createClassEntityExecutor.execute(
CreateClassesFromApiRequest.create(
ChangeRequestId.generate(),
Expand Down Expand Up @@ -215,4 +220,79 @@ public CompletableFuture<EntityComments> getEntityDiscussionThreads(String entit
return entityDiscussionExecutor.execute(GetEntityCommentsRequest.create(ProjectId.valueOf(projectId), entityIri), SecurityContextHelper.getExecutionContext())
.thenApply(GetEntityCommentsResponse::comments);
}


public void validateCreateEntityRequest(String projectId, CreateEntityDto createEntityDto) {
validateTitle(createEntityDto.title());
validateProjectId(projectId);
validateEntityParents(projectId, createEntityDto.parent());
}

private void validateTitle(String title) {
if(title == null || title.isBlank()){
throw new IllegalArgumentException("Title title cannot be empty");
}
if (hasEscapeCharacters(title)) {
throw new IllegalArgumentException(MessageFormat.format("Title has escape characters: {0}. please remove any escape characters", title));
}
}

private void validateProjectId(String projectId) {
boolean projectExists;
try {
projectExists = this.isExistingProject(projectId).get();
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("Could not verify if projectId:" + projectId + " is valid!", e);
throw new RuntimeException(e);
}
if (!projectExists) {
throw new IllegalArgumentException("Invalid Project ID: " + projectId);
}
}

private void validateEntityParents(String projectId, String parent) {
if (parent == null || parent.isEmpty()) {
throw new IllegalArgumentException("At least a parent should be specified!");
}
Set<String> existingParents;
try {
existingParents = this.getExistingEntities(projectId, parent).get();
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("Could not verify if parent:" + parent + " is valid!", e);
throw new RuntimeException(e);
}
boolean isValid = existingParents.stream().anyMatch(existingParent -> existingParent.equals(parent));
if (!isValid) {
throw new IllegalArgumentException("Invalid Entity Parent: " + parent);
}
}

private void validateEntityExists(String projectId, String entity){
if (entity == null || entity.isEmpty()) {
throw new IllegalArgumentException("At least an entityUri should be specified!");
}
Set<String> existingEntities;
try {
existingEntities = this.getExistingEntities(projectId, entity).get();
} catch (InterruptedException | ExecutionException e) {
LOGGER.error("Could not verify if parent:" + entity + " is valid!", e);
throw new RuntimeException(e);
}
boolean isValid = existingEntities.stream().anyMatch(existingParent -> existingParent.equals(entity));
if (!isValid) {
throw new EntityIsMissingException("Invalid Entity IRI: " + entity);
}
}

public static boolean hasEscapeCharacters(String input) {
for (int i = 0; i < input.length() - 1; i++) {
if (input.charAt(i) == '\\') {
char nextChar = input.charAt(i + 1);
if ("ntbrf\"'\\".indexOf(nextChar) != -1) {
return true;
}
}
}
return false;
}
}

This file was deleted.

0 comments on commit c2add51

Please sign in to comment.