diff --git a/charts/fairspace/templates/project/stateful-set.yaml b/charts/fairspace/templates/project/stateful-set.yaml index 79fa34445..a9468cb30 100644 --- a/charts/fairspace/templates/project/stateful-set.yaml +++ b/charts/fairspace/templates/project/stateful-set.yaml @@ -100,7 +100,7 @@ spec: {{- end }} livenessProbe: httpGet: - path: /liveness + path: /actuator/health/liveness port: 8091 initialDelaySeconds: {{ .Values.saturn.livenessProbe.initialDelaySeconds }} periodSeconds: {{ .Values.saturn.livenessProbe.periodSeconds }} @@ -108,8 +108,8 @@ spec: timeoutSeconds: {{ .Values.saturn.livenessProbe.timeoutSeconds }} readinessProbe: httpGet: - path: /api/health/ - port: 8090 + path: /actuator/health/readiness + port: 8091 periodSeconds: {{ .Values.saturn.readinessProbe.periodSeconds }} successThreshold: {{ .Values.saturn.readinessProbe.successThreshold }} timeoutSeconds: {{ .Values.saturn.readinessProbe.timeoutSeconds }} @@ -222,4 +222,4 @@ spec: storageClassName: {{ index .Values "saturn" "persistence" "extra-file-storage" "storageClass" | quote }} {{- end }} {{- end }} -{{- end }} \ No newline at end of file +{{- end }} diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/auth/PermissionService.java b/projects/saturn/src/main/java/io/fairspace/saturn/auth/PermissionService.java deleted file mode 100644 index 764f2ef1b..000000000 --- a/projects/saturn/src/main/java/io/fairspace/saturn/auth/PermissionService.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.fairspace.saturn.auth; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; - -import io.fairspace.saturn.services.users.UserService; - -@Service -@RequiredArgsConstructor -public class PermissionService { - - private final UserService userService; - - // todo: add tests - public boolean hasMetadataQueryPermission() { - var user = userService.currentUser(); - return user != null && user.isCanQueryMetadata(); - } -} diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/auth/RequestContext.java b/projects/saturn/src/main/java/io/fairspace/saturn/auth/RequestContext.java index 9437b97ae..07529831f 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/auth/RequestContext.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/auth/RequestContext.java @@ -55,10 +55,6 @@ public static SaturnClaims getClaims() { return getJwt().map(Jwt::getClaims).map(SaturnClaims::from).orElseGet(SaturnClaims::emptyClaims); } - public static String getIdTokenString() { - return getJwt().map(Jwt::getTokenValue).orElse(null); - } - private static Optional getAuthentication() { return Optional.ofNullable(SecurityContextHolder.getContext().getAuthentication()); } diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/config/ViewsConfig.java b/projects/saturn/src/main/java/io/fairspace/saturn/config/ViewsConfig.java index 6a9a1dad4..2ee471499 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/config/ViewsConfig.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/config/ViewsConfig.java @@ -119,6 +119,7 @@ public static class Column { public Integer displayIndex = Integer.MAX_VALUE; public String rdfType; + public int priority; } diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/config/ViewsConfigProperties.java b/projects/saturn/src/main/java/io/fairspace/saturn/config/ViewsConfigProperties.java new file mode 100644 index 000000000..2db2562d2 --- /dev/null +++ b/projects/saturn/src/main/java/io/fairspace/saturn/config/ViewsConfigProperties.java @@ -0,0 +1,139 @@ +package io.fairspace.saturn.config; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonSetter; +import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.Nulls; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; + +@Component +@PropertySource("classpath:views.yaml") +public class ViewsConfigProperties { + + // private Map nameToViewConfigMap; + + public List views = new ArrayList<>(); + + public enum ColumnType { + Text, + Set, + Term, + TermSet, + Number, + Date, + Boolean, + Identifier; + + public boolean isSet() { + return this == Set || this == TermSet; + } + + @JsonValue + public String getName() { + return this.name(); + } + + private static final Map mapping = new HashMap<>(); + + static { + for (ColumnType type : values()) { + mapping.put(type.name().toLowerCase(), type); + } + } + + @JsonCreator + public static ColumnType forName(String name) { + if (name == null) { + return null; + } + name = name.toLowerCase(); + if (!mapping.containsKey(name)) { + throw new IllegalArgumentException("Unknown column type: " + name); + } + return mapping.get(name); + } + } + + public static class View { + /** + * The view name. + */ + @NotBlank + public String name; + /** + * The view title. + */ + @NotBlank + public String title; + /** + * The name of the items that appear as rows. + */ + public String itemName; + /** + * The max count value to be requested for a view total count. + * If total count is greater than this max value, the total count value will look like 'more than 1000' on FE. + * This is to prevent performance issues when the total count is too large. + */ + public Long maxDisplayCount; + /** + * The URLs of the types of entities that should be indexed in this view. + */ + @JsonSetter(nulls = Nulls.AS_EMPTY) + public List types; + /** + * Specifies which other views (and which columns) to embed in this view. + */ + @JsonSetter(nulls = Nulls.AS_EMPTY) + public List join; + /** + * The columns of the view, not including columns from joined views. + */ + @JsonSetter(nulls = Nulls.AS_EMPTY) + public List columns; + + public static class Column { + @NotBlank + public String name; + + @NotBlank + public String title; + + @NotNull + public ColumnType type; + + @NotBlank + public String source; + // displayIndex determines the order of columns on the view page. + @NotNull + public Integer displayIndex = Integer.MAX_VALUE; + + public String rdfType; + + public int priority; + } + + public static class JoinView { + @NotBlank + public String view; + + @NotBlank + public String on; + + public boolean reverse = false; + + @JsonSetter(nulls = Nulls.AS_EMPTY) + public List include; + // displayIndex determines the order of columns on the view page, for joinView it is the column displaying + // the related entity + public Integer displayIndex = Integer.MAX_VALUE; + } + } +} diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/controller/SparqlController.java b/projects/saturn/src/main/java/io/fairspace/saturn/controller/SparqlController.java index caa5656fd..c2296b014 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/controller/SparqlController.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/controller/SparqlController.java @@ -2,14 +2,15 @@ import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import io.fairspace.saturn.config.Services; import io.fairspace.saturn.controller.validation.ValidSparqlReadQuery; +import io.fairspace.saturn.services.AccessDeniedException; import io.fairspace.saturn.services.views.SparqlQueryService; @RestController @@ -20,6 +21,8 @@ public class SparqlController { private final SparqlQueryService sparqlQueryService; + private final Services services; + /** * Execute a read-only SPARQL query. * @@ -27,8 +30,13 @@ public class SparqlController { * @return the result of the query (JSON) */ @PostMapping(value = "/query", consumes = "application/sparql-query", produces = "application/json") - @PreAuthorize("@permissionService.hasMetadataQueryPermission()") + // todo: uncomment the line below and remove the metadataPermissions.hasMetadataQueryPermission() call once + // the MetadataPermissions is available in the IoC container + // @PreAuthorize("@metadataPermissions.hasMetadataQueryPermission()") public ResponseEntity executeSparqlQuery(@ValidSparqlReadQuery @RequestBody String sparqlQuery) { + if (!services.getMetadataPermissions().hasMetadataQueryPermission()) { + throw new AccessDeniedException("You do not have permission to execute SPARQL queries."); + } var json = sparqlQueryService.executeQuery(sparqlQuery); return ResponseEntity.ok(json); } diff --git a/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/MetadataPermissions.java b/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/MetadataPermissions.java index 27e6b381e..fd0752fd1 100644 --- a/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/MetadataPermissions.java +++ b/projects/saturn/src/main/java/io/fairspace/saturn/services/metadata/MetadataPermissions.java @@ -53,4 +53,9 @@ public boolean canWriteMetadata(Resource resource) { } return userService.currentUser().isCanAddSharedMetadata(); } + + public boolean hasMetadataQueryPermission() { + var user = userService.currentUser(); + return user != null && user.isCanQueryMetadata(); + } } diff --git a/projects/saturn/src/main/resources/application.yaml b/projects/saturn/src/main/resources/application.yaml index 237b34831..7f26388a5 100644 --- a/projects/saturn/src/main/resources/application.yaml +++ b/projects/saturn/src/main/resources/application.yaml @@ -41,7 +41,7 @@ application: # Base IRI for all metadata entities metadataBaseIRI: ${METADATA_BASE_IRI:http://localhost/iri/} # Jena's TDB2 database path - datasetPath: ${DATASET_PATH:/Users/anton/git/rdm/fairspace/projects/saturn/data/db} + datasetPath: ${DATASET_PATH:data/db} # Path of the transaction log transactionLogPath: ${TRANSACTION_LOG_PATH:data/log} bulkTransactions: ${BULK_TRANSACTIONS:true}