Skip to content

Commit

Permalink
Merge pull request #639 from molgenis/revert-563-feat/M10506-views
Browse files Browse the repository at this point in the history
Revert "Feat: add views on tables"
  • Loading branch information
marikaris authored Feb 19, 2024
2 parents d9d22bb + 01552bc commit bc501de
Show file tree
Hide file tree
Showing 17 changed files with 39 additions and 842 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public class AuditEventPublisher implements ApplicationEventPublisherAware {
public static final String LIST_OBJECTS = "LIST_OBJECTS";
public static final String UPLOAD_OBJECT = "UPLOAD_OBJECT";
public static final String COPY_OBJECT = "COPY_OBJECT";
public static final String CREATE_LINKED_OBJECT = "CREATE_LINKED_OBJECT";
public static final String MOVE_OBJECT = "MOVE_OBJECT";
public static final String GET_OBJECT = "GET_OBJECT";
public static final String PREVIEW_OBJECT = "PREVIEW_OBJECT";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
import static java.util.concurrent.CompletableFuture.completedFuture;
import static org.molgenis.armadillo.audit.AuditEventPublisher.*;
import static org.molgenis.armadillo.controller.ArmadilloUtils.getLastCommandLocation;
import static org.molgenis.armadillo.security.RunAs.runAsSystem;
import static org.molgenis.armadillo.storage.ArmadilloStorageService.LINK_FILE;
import static org.molgenis.armadillo.storage.ArmadilloStorageService.PARQUET;
import static org.obiba.datashield.core.DSMethodType.AGGREGATE;
import static org.obiba.datashield.core.DSMethodType.ASSIGN;
import static org.springframework.http.HttpStatus.*;
Expand All @@ -18,15 +15,12 @@

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import java.io.InputStream;
import java.security.Principal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
Expand All @@ -35,12 +29,9 @@
import org.molgenis.armadillo.command.ArmadilloCommandDTO;
import org.molgenis.armadillo.command.Commands;
import org.molgenis.armadillo.exceptions.ExpressionException;
import org.molgenis.armadillo.exceptions.UnknownObjectException;
import org.molgenis.armadillo.exceptions.UnknownVariableException;
import org.molgenis.armadillo.model.Workspace;
import org.molgenis.armadillo.service.DSEnvironmentCache;
import org.molgenis.armadillo.service.ExpressionRewriter;
import org.molgenis.armadillo.storage.ArmadilloLinkFile;
import org.molgenis.armadillo.storage.ArmadilloStorageService;
import org.molgenis.r.RServerResult;
import org.molgenis.r.model.RPackage;
Expand All @@ -50,7 +41,6 @@
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;

@Tag(name = "DataSHIELD", description = "Core API that interacts with the DataSHIELD environments")
@SecurityRequirement(name = "bearerAuth")
Expand Down Expand Up @@ -135,43 +125,39 @@ public ResponseEntity<Void> tableExists(
summary = "Load table",
description = "Load a table",
security = {@SecurityRequirement(name = "jwt")})
@ApiResponses(
value = {
@ApiResponse(responseCode = "200", description = "Object loaded successfully"),
@ApiResponse(
responseCode = "404",
description = "Unknown project or object",
content = @Content(mediaType = "application/json")),
@ApiResponse(
responseCode = "401",
description = "Unauthorized",
content = @Content(mediaType = "application/json"))
})
@PostMapping(value = "/load-table")
public CompletableFuture<ResponseEntity<Void>> loadTable(
Principal principal,
@Valid @Pattern(regexp = SYMBOL_RE) @RequestParam String symbol,
@Valid @Pattern(regexp = TABLE_RESOURCE_REGEX) @RequestParam String table,
@Valid @Pattern(regexp = SYMBOL_CSV_RE) @RequestParam(required = false) String variables,
@RequestParam(defaultValue = "false") boolean async) {

java.util.regex.Pattern tableResourcePattern =
java.util.regex.Pattern.compile(TABLE_RESOURCE_REGEX);
HashMap<String, Object> data = getMatchedData(tableResourcePattern, table, TABLE);
data.put(SYMBOL, symbol);
String project = (String) data.get(PROJECT);
String objectName = String.format(PATH_FORMAT, data.get(FOLDER), data.get(TABLE));
if (storage.hasObject(project, objectName + LINK_FILE)) {
return loadTableFromLinkFile(project, objectName, variables, principal, data, symbol, async);
} else if (storage.hasObject(project, objectName + PARQUET)) {
var variableList = getVariableList(variables);
return doLoadTable(symbol, table, variableList, principal, data, async);
} else {
if (!storage.tableExists(
(String) data.get(PROJECT),
String.format(PATH_FORMAT, data.get(FOLDER), data.get(TABLE)))) {
data = new HashMap<>(data);
data.put(MESSAGE, "Table not found");
auditEventPublisher.audit(principal, LOAD_TABLE_FAILURE, data);
throw new ResponseStatusException(
NOT_FOUND, format("Project '%s' has no object '%s'", project, objectName));
return completedFuture(notFound().build());
}
var variableList =
Optional.ofNullable(variables).map(it -> it.split(",")).stream()
.flatMap(Arrays::stream)
.map(String::trim)
.toList();
var result =
auditEventPublisher.audit(
commands.loadTable(symbol, table, variableList), principal, LOAD_TABLE, data);
return async
? completedFuture(created(getLastCommandLocation()).body(null))
: result
.thenApply(ResponseEntity::ok)
.exceptionally(t -> status(INTERNAL_SERVER_ERROR).build());
}

@Operation(
Expand Down Expand Up @@ -474,75 +460,4 @@ HashMap<String, Object> getMatchedData(
groups.put(resource, matcher.group(3));
return groups;
}

public List<String> getVariableList(String variables) {
return Optional.ofNullable(variables).map(it -> it.split(",")).stream()
.flatMap(Arrays::stream)
.map(String::trim)
.toList();
}

private CompletableFuture<ResponseEntity<Void>> doLoadTable(
String symbol,
String table,
List<String> variableList,
Principal principal,
Map<String, Object> data,
Boolean async) {
var result =
auditEventPublisher.audit(
commands.loadTable(symbol, table, variableList), principal, LOAD_TABLE, data);
return async
? completedFuture(created(getLastCommandLocation()).body(null))
: result
.thenApply(ResponseEntity::ok)
.exceptionally(t -> status(INTERNAL_SERVER_ERROR).build());
}

protected List<String> getLinkedVariables(ArmadilloLinkFile linkFile, String variables) {
List<String> allowedVariables = List.of(linkFile.getVariables().split(","));
List<String> variableList = getVariableList(variables);
var invalidVariables =
variableList.stream().filter(element -> !allowedVariables.contains(element)).toList();
if (invalidVariables.size() > 0) {
String invalid = invalidVariables.toString();
throw new UnknownVariableException(linkFile.getProject(), linkFile.getLinkObject(), invalid);
}
return variableList.size() == 0
? allowedVariables
: variableList.stream().filter(allowedVariables::contains).toList();
}

private CompletableFuture<ResponseEntity<Void>> loadTableFromLinkFile(
String project,
String objectName,
String variables,
Principal principal,
HashMap<String, Object> data,
String symbol,
Boolean async) {
InputStream armadilloLinkFileStream = storage.loadObject(project, objectName + LINK_FILE);
ArmadilloLinkFile linkFile =
storage.createArmadilloLinkFileFromStream(armadilloLinkFileStream, project, objectName);
String sourceProject = linkFile.getSourceProject();
String sourceObject = linkFile.getSourceObject();
if (runAsSystem(() -> storage.hasObject(sourceProject, sourceObject + PARQUET))) {
List<String> variableList = getLinkedVariables(linkFile, variables);
HashMap<String, Object> finalData = data;
return runAsSystem(
() ->
doLoadTable(
symbol,
sourceProject + "/" + sourceObject,
variableList,
principal,
finalData,
async));
} else {
data = new HashMap<>(data);
data.put(MESSAGE, "Object not found");
auditEventPublisher.audit(principal, LOAD_TABLE_FAILURE, data);
throw new UnknownObjectException(sourceProject, sourceObject);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package org.molgenis.armadillo.controller;

import static org.apache.logging.log4j.util.Strings.concat;
import static org.molgenis.armadillo.audit.AuditEventPublisher.*;
import static org.molgenis.armadillo.storage.ArmadilloStorageService.LINK_FILE;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
Expand All @@ -24,10 +22,8 @@
import jakarta.validation.constraints.NotEmpty;
import java.io.IOException;
import java.security.Principal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.molgenis.armadillo.audit.AuditEventPublisher;
import org.molgenis.armadillo.exceptions.FileProcessingException;
import org.molgenis.armadillo.exceptions.UnknownObjectException;
Expand Down Expand Up @@ -151,57 +147,6 @@ public void copyObject(
Map.of(PROJECT, project, "from", object, "to", requestBody.name()));
}

@Operation(
summary = "Create a view from an existing table in another project",
description =
"The view you're creating will be a symbolic link to selected variables of an existing table. It will"
+ "look and respond like a table, but it will not take up duplicated resources")
@ApiResponses(
value = {
@ApiResponse(responseCode = "204", description = "Link successfully created"),
@ApiResponse(responseCode = "404", description = "Unknown project or object"),
@ApiResponse(responseCode = "409", description = "Object already exists"),
@ApiResponse(responseCode = "401", description = "Unauthorized")
})
@PostMapping(
value = "/projects/{project}/objects/link",
consumes = {APPLICATION_JSON_VALUE})
@ResponseStatus(NO_CONTENT)
public void createLinkedObject(
Principal principal,
@PathVariable String project,
@RequestBody LinkedObjectRequestBody requestBody) {
var variableList =
Optional.ofNullable(requestBody.variables()).map(it -> it.split(",")).stream()
.flatMap(Arrays::stream)
.map(String::trim)
.toList();
auditor.audit(
() -> {
try {
storage.createLinkedObject(
requestBody.sourceProject(),
requestBody.sourceObjectName(),
requestBody.linkedObject(),
project,
requestBody.variables());
} catch (IOException e) {
throw new RuntimeException(e);
}
},
principal,
CREATE_LINKED_OBJECT,
Map.of(
PROJECT,
project,
OBJECT,
requestBody.linkedObject() + LINK_FILE,
"source",
concat(concat(project, "/"), requestBody.linkedObject()),
"columns",
variableList));
}

@Operation(
summary = "Move an object within a project",
description =
Expand Down

This file was deleted.

Loading

0 comments on commit bc501de

Please sign in to comment.