Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(hmi-server): download code #2672

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
package software.uncharted.terarium.hmiserver.controller.dataservice;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
Expand All @@ -22,38 +22,22 @@
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.server.ResponseStatusException;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import software.uncharted.terarium.hmiserver.models.dataservice.PresignedURL;
import software.uncharted.terarium.hmiserver.models.dataservice.ResponseDeleted;
import software.uncharted.terarium.hmiserver.models.dataservice.code.Code;
import software.uncharted.terarium.hmiserver.models.dataservice.code.CodeFile;
import software.uncharted.terarium.hmiserver.models.extractionservice.ExtractionResponse;
import software.uncharted.terarium.hmiserver.proxies.github.GithubProxy;
import software.uncharted.terarium.hmiserver.proxies.jsdelivr.JsDelivrProxy;
import software.uncharted.terarium.hmiserver.security.Roles;
import software.uncharted.terarium.hmiserver.service.data.CodeService;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

@RequestMapping("/code-asset")
@RestController
@Slf4j
Expand Down Expand Up @@ -91,7 +75,7 @@ public ResponseEntity<List<Code>> getCodes(
@RequestParam(name = "page", defaultValue = "0", required = false) final Integer page) {
try {
return ResponseEntity.ok(codeService.getCode(pageSize, page));
} catch (IOException e) {
} catch (final IOException e) {
log.error("Unable to get code resources", e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
Expand All @@ -117,7 +101,7 @@ public ResponseEntity<Code> createCode(@RequestBody Code code) {
try {
code = codeService.createCode(code);
return ResponseEntity.status(HttpStatus.CREATED).body(code);
} catch (IOException e) {
} catch (final IOException e) {
log.error("Unable to create code resource", e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
Expand All @@ -141,14 +125,14 @@ public ResponseEntity<Code> createCode(@RequestBody Code code) {
@ApiResponse(responseCode = "404", description = "There was no code resource found", content = @Content),
@ApiResponse(responseCode = "500", description = "There was an issue retrieving the code resource from the data store", content = @Content)
})
public ResponseEntity<Code> getCode(@PathVariable("id") UUID id) {
public ResponseEntity<Code> getCode(@PathVariable("id") final UUID id) {
try {
Optional<Code> code = codeService.getCode(id);
final Optional<Code> code = codeService.getCode(id);
if (code.isEmpty()) {
return ResponseEntity.noContent().build();
}
return ResponseEntity.ok(code.get());
} catch (IOException e) {
} catch (final IOException e) {
log.error("Unable to get code resource", e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
Expand All @@ -172,8 +156,8 @@ public ResponseEntity<Code> getCode(@PathVariable("id") UUID id) {
@ApiResponse(responseCode = "500", description = "There was an issue updating the code resource", content = @Content)
})
public ResponseEntity<Code> updateCode(
@PathVariable("id") UUID codeId,
@RequestBody Code code) {
@PathVariable("id") final UUID codeId,
@RequestBody final Code code) {

try {
code.setId(codeId);
Expand All @@ -183,7 +167,7 @@ public ResponseEntity<Code> updateCode(
}
return ResponseEntity.ok(updated.get());

} catch (IOException e) {
} catch (final IOException e) {
log.error("Unable to update code resource", e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
Expand All @@ -205,11 +189,11 @@ public ResponseEntity<Code> updateCode(
@ApiResponse(responseCode = "200", description = "Code resource deleted.", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = ResponseDeleted.class))),
@ApiResponse(responseCode = "500", description = "There was an issue deleting the code resource", content = @Content)
})
public ResponseEntity<ResponseDeleted> deleteCode(@PathVariable("id") UUID id) {
public ResponseEntity<ResponseDeleted> deleteCode(@PathVariable("id") final UUID id) {

try {
codeService.deleteCode(id);
} catch (IOException e) {
} catch (final IOException e) {
log.error("Unable to delete code resource", e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
Expand All @@ -234,14 +218,14 @@ public ResponseEntity<ResponseDeleted> deleteCode(@PathVariable("id") UUID id) {
@ApiResponse(responseCode = "200", description = "Code file found.", content = @Content(mediaType = MediaType.TEXT_PLAIN_VALUE)),
@ApiResponse(responseCode = "500", description = "There was an issue retrieving the code file from the data store", content = @Content)
})
public ResponseEntity<String> getCodeFileAsText(@PathVariable("id") UUID codeId,
@RequestParam("filename") String filename) {
public ResponseEntity<String> getCodeFileAsText(@PathVariable("id") final UUID codeId,
@RequestParam("filename") final String filename) {

try (CloseableHttpClient httpclient = HttpClients.custom()
try (final CloseableHttpClient httpclient = HttpClients.custom()
.disableRedirectHandling()
.build()) {

Optional<PresignedURL> url = codeService.getDownloadUrl(codeId, filename);
final Optional<PresignedURL> url = codeService.getDownloadUrl(codeId, filename);
if (url.isEmpty()) {
return ResponseEntity.notFound().build();
}
Expand All @@ -252,7 +236,7 @@ public ResponseEntity<String> getCodeFileAsText(@PathVariable("id") UUID codeId,

return ResponseEntity.ok(textFileAsString);

} catch (Exception e) {
} catch (final Exception e) {
log.error("Unable to GET file as string data", e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
Expand All @@ -261,6 +245,31 @@ public ResponseEntity<String> getCodeFileAsText(@PathVariable("id") UUID codeId,

}


@GetMapping("/{id}/download-url")
@Secured(Roles.USER)
@Operation(summary = "Gets a presigned url to download the code file")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Presigned url generated.", content = @Content(mediaType = "application/json", schema = @io.swagger.v3.oas.annotations.media.Schema(implementation = PresignedURL.class))),
@ApiResponse(responseCode = "404", description = "There was no code resource found", content = @Content),
@ApiResponse(responseCode = "500", description = "There was an issue retrieving the presigned url", content = @Content)
})
public ResponseEntity<PresignedURL> getDownloadURL(@PathVariable("id") final UUID id, @RequestParam("filename") final String filename) {
try {

final Optional<PresignedURL> url = codeService.getDownloadUrl(id, filename);
return url.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());

} catch (final Exception e) {
final String error = "Unable to get download url";
log.error(error, e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
error);
}
}


@GetMapping("/{id}/upload-url")
@Secured(Roles.USER)
@Operation(summary = "Gets a presigned url to upload the code file")
Expand Down Expand Up @@ -304,12 +313,12 @@ public ResponseEntity<PresignedURL> getUploadURL(
public ResponseEntity<Integer> uploadFile(
@PathVariable("id") final UUID codeId,
@RequestParam("filename") final String filename,
@RequestPart("file") MultipartFile input) throws IOException {
@RequestPart("file") final MultipartFile input) throws IOException {

log.debug("Uploading code {} to project", codeId);

byte[] fileAsBytes = input.getBytes();
HttpEntity fileEntity = new ByteArrayEntity(fileAsBytes, ContentType.APPLICATION_OCTET_STREAM);
final byte[] fileAsBytes = input.getBytes();
final HttpEntity fileEntity = new ByteArrayEntity(fileAsBytes, ContentType.APPLICATION_OCTET_STREAM);
return uploadCodeHelper(codeId, filename, fileEntity);

}
Expand All @@ -332,8 +341,8 @@ public ResponseEntity<Integer> uploadCodeFromGithub(
log.debug("Uploading code file from github to dataset {}", codeId);

// download file from GitHub
String fileString = jsdelivrProxy.getGithubCode(repoOwnerAndName, path).getBody();
HttpEntity fileEntity = new StringEntity(fileString, ContentType.TEXT_PLAIN);
final String fileString = jsdelivrProxy.getGithubCode(repoOwnerAndName, path).getBody();
final HttpEntity fileEntity = new StringEntity(fileString, ContentType.TEXT_PLAIN);
return uploadCodeHelper(codeId, filename, fileEntity);

}
Expand Down Expand Up @@ -361,18 +370,18 @@ public ResponseEntity<Integer> uploadCodeFromGithubRepo(
try (final CloseableHttpClient httpClient = HttpClients.custom()
.build()) {

String githubApiUrl = "https://api.github.com/repos/" + repoOwnerAndName + "/zipball/";
final String githubApiUrl = "https://api.github.com/repos/" + repoOwnerAndName + "/zipball/";

// get github repo zip
HttpGet httpGet = new HttpGet(githubApiUrl);
HttpResponse response = httpClient.execute(httpGet);
final HttpGet httpGet = new HttpGet(githubApiUrl);
final HttpResponse response = httpClient.execute(httpGet);
final byte[] zipBytes = response.getEntity().getContent().readAllBytes();

HttpEntity fileEntity = new ByteArrayEntity(zipBytes, ContentType.APPLICATION_OCTET_STREAM);
final HttpEntity fileEntity = new ByteArrayEntity(zipBytes, ContentType.APPLICATION_OCTET_STREAM);

return uploadCodeHelper(codeId, repoName, fileEntity);

} catch (Exception e) {
} catch (final Exception e) {
log.error("Unable to GET file as string data", e);
throw new ResponseStatusException(
org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR,
Expand All @@ -389,9 +398,9 @@ public ResponseEntity<Integer> uploadCodeFromGithubRepo(
* @param codeHttpEntity The entity containing the code to upload
* @return A response containing the status of the upload
*/
private ResponseEntity<Integer> uploadCodeHelper(UUID codeId, String fileName, HttpEntity codeHttpEntity) {
private ResponseEntity<Integer> uploadCodeHelper(final UUID codeId, final String fileName, final HttpEntity codeHttpEntity) {

try (CloseableHttpClient httpclient = HttpClients.custom()
try (final CloseableHttpClient httpclient = HttpClients.custom()
.disableRedirectHandling()
.build()) {

Expand All @@ -416,7 +425,7 @@ private ResponseEntity<Integer> uploadCodeHelper(UUID codeId, String fileName, H

return ResponseEntity.ok(response.getStatusLine().getStatusCode());

} catch (Exception e) {
} catch (final Exception e) {
log.error("Unable to PUT artifact data", e);
return ResponseEntity.internalServerError().build();
}
Expand Down
Loading