generated from codeforamerica/form-flow-starter-app
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into fix_background_color
- Loading branch information
Showing
132 changed files
with
8,229 additions
and
868 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,4 +38,6 @@ out/ | |
.vscode/ | ||
|
||
### Mac OS ### | ||
.DS_Store | ||
.DS_Store | ||
|
||
*.log |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#!/bin/bash | ||
set -euo pipefail | ||
|
||
migrations_path="$(dirname $0)/../src/main/resources/db/migration" | ||
|
||
if [ ! -d "$migrations_path" ]; then | ||
echo "Migration directory '$migrations_path' does not exist. Creating..." | ||
mkdir -p "$migrations_path" | ||
fi | ||
|
||
migrations_path=$(realpath "$migrations_path") | ||
|
||
printf "Generating migration file. \nEnter Description (e.g. 'Create admin users'): " | ||
read description | ||
|
||
filename="V$(date +%Y.%m.%d.%H.%M.%S)__$(echo "$description" | sed -E 's/[^A-Z]+/_/ig').sql" | ||
echo "Creating ${filename}." | ||
touch "$migrations_path/$filename" | ||
|
||
echo "Hit enter to open." | ||
read | ||
open -a "IntelliJ IDEA.app" "$migrations_path/$filename" |
157 changes: 157 additions & 0 deletions
157
src/main/java/org/ladocuploader/app/FileExportController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package org.ladocuploader.app; | ||
|
||
|
||
|
||
import com.opencsv.exceptions.CsvDataTypeMismatchException; | ||
import com.opencsv.exceptions.CsvRequiredFieldEmptyException; | ||
|
||
|
||
import formflow.library.config.FlowConfiguration; | ||
import formflow.library.data.Submission; | ||
import formflow.library.data.SubmissionRepositoryService; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpSession; | ||
|
||
|
||
import java.io.IOException; | ||
import java.util.*; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.commons.text.StringEscapeUtils; | ||
import org.ladocuploader.app.csv.CsvDocument; | ||
import org.ladocuploader.app.csv.CsvService; | ||
import org.ladocuploader.app.csv.enums.CsvType; | ||
|
||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | ||
import org.springframework.context.MessageSource; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.server.ResponseStatusException; | ||
|
||
import static formflow.library.FormFlowController.getSubmissionIdForFlow; | ||
|
||
@Controller | ||
@EnableAutoConfiguration | ||
@Slf4j | ||
@RequestMapping("/download-csv") | ||
public class FileExportController { | ||
|
||
private final MessageSource messageSource; | ||
|
||
private final SubmissionRepositoryService submissionRepositoryService; | ||
|
||
private final List<FlowConfiguration> flowConfigurations; | ||
|
||
private final CsvService csvService; | ||
|
||
public FileExportController(MessageSource messageSource, | ||
SubmissionRepositoryService submissionRepositoryService, | ||
List<FlowConfiguration> flowConfigurations, CsvService csvService) { | ||
|
||
this.submissionRepositoryService = submissionRepositoryService; | ||
this.flowConfigurations = flowConfigurations; | ||
this.messageSource = messageSource; | ||
this.csvService = csvService; | ||
} | ||
|
||
|
||
@GetMapping("{flow}/pg/{submissionId}") | ||
ResponseEntity<?> downloadPGCsv( | ||
@PathVariable String flow, | ||
@PathVariable String submissionId, | ||
HttpSession httpSession, | ||
HttpServletRequest request, | ||
Locale locale | ||
) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { | ||
|
||
String cleanedFlow = StringEscapeUtils.escapeHtml4(flow); | ||
String cleanedSubmissionId = StringEscapeUtils.escapeHtml4(submissionId); | ||
|
||
log.info("GET downloadCSV ParentGuardian (url: {}): flow: {}, submissionId: {}", request.getRequestURI().toLowerCase(), | ||
cleanedFlow, cleanedSubmissionId); | ||
|
||
return handleCsvGeneration(cleanedFlow, cleanedSubmissionId, httpSession, locale, CsvType.PARENT_GUARDIAN); | ||
} | ||
|
||
@GetMapping("{flow}/student/{submissionId}") | ||
ResponseEntity<?> downloadStudentCsv( | ||
@PathVariable String flow, | ||
@PathVariable String submissionId, | ||
HttpSession httpSession, | ||
HttpServletRequest request, | ||
Locale locale | ||
) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { | ||
|
||
String cleanedFlow = StringEscapeUtils.escapeHtml4(flow); | ||
String cleanedSubmissionId = StringEscapeUtils.escapeHtml4(submissionId); | ||
|
||
log.info("GET downloadCSV Student (url: {}): flow: {}, submissionId: {}", request.getRequestURI().toLowerCase(), | ||
cleanedFlow, cleanedSubmissionId); | ||
|
||
return handleCsvGeneration(cleanedFlow, cleanedSubmissionId, httpSession, locale, CsvType.STUDENT); | ||
} | ||
|
||
@GetMapping("{flow}/rel/{submissionId}") | ||
ResponseEntity<?> downloadRelCsv( | ||
@PathVariable String flow, | ||
@PathVariable String submissionId, | ||
HttpSession httpSession, | ||
HttpServletRequest request, | ||
Locale locale | ||
) throws IOException, CsvRequiredFieldEmptyException, CsvDataTypeMismatchException { | ||
|
||
String cleanedFlow = StringEscapeUtils.escapeHtml4(flow); | ||
String cleanedSubmissionId = StringEscapeUtils.escapeHtml4(submissionId); | ||
|
||
log.info("GET downloadCSV Relationship (url: {}): flow: {}, submissionId: {}", request.getRequestURI().toLowerCase(), | ||
cleanedFlow, cleanedSubmissionId); | ||
|
||
return handleCsvGeneration(cleanedFlow, cleanedSubmissionId, httpSession, locale, CsvType.RELATIONSHIP); | ||
} | ||
|
||
protected static void throwNotFoundError(String flow, String message) { | ||
throw new ResponseStatusException(HttpStatus.NOT_FOUND, | ||
String.format("There was a problem with the request during CSV Generation (flow: %s): %s", | ||
flow, message)); | ||
|
||
} | ||
|
||
protected Boolean doesFlowExist(String flow) { | ||
return flowConfigurations.stream().anyMatch( | ||
flowConfiguration -> flowConfiguration.getName().equals(flow) | ||
); | ||
} | ||
|
||
private ResponseEntity handleCsvGeneration(String flow, String submissionId, HttpSession httpSession, | ||
Locale locale, CsvType csvType) throws CsvRequiredFieldEmptyException, CsvDataTypeMismatchException, IOException { | ||
|
||
if (!doesFlowExist(flow)) { | ||
throwNotFoundError(flow, String.format("Could not find flow %s in your application's flow configuration.", flow)); | ||
} | ||
// TODO: get list of submissions based on another column - like transmission? | ||
Optional<Submission> maybeSubmission = submissionRepositoryService.findById(UUID.fromString(submissionId)); | ||
if (getSubmissionIdForFlow(httpSession, flow).toString().equals(submissionId) && maybeSubmission.isPresent()) { | ||
log.info("Generating CSV with submission_id: " + submissionId); | ||
Submission submission = maybeSubmission.get(); | ||
CsvDocument csvDoc = csvService.generateCsvFormattedData(List.of(submission), csvType); | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.add(HttpHeaders.CONTENT_DISPOSITION, | ||
"attachment; filename=%s".formatted(csvService.generateCsvName(submission.getFlow(), csvType))); | ||
return ResponseEntity | ||
.ok() | ||
.contentType(MediaType.APPLICATION_OCTET_STREAM) | ||
.headers(headers) | ||
.body(csvDoc.getCsvData()); | ||
} else { | ||
log.error("Attempted to download PDF with submission_id: " + submissionId + " but session_id was: " | ||
+ httpSession.getAttribute("id")); | ||
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(messageSource.getMessage("error.forbidden", null, locale)); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package org.ladocuploader.app.cli; | ||
|
||
import java.io.IOException; | ||
|
||
public interface FtpsClient { | ||
|
||
void uploadFile(String zipFilename, byte[] data) throws IOException; | ||
} |
62 changes: 62 additions & 0 deletions
62
src/main/java/org/ladocuploader/app/cli/FtpsClientImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package org.ladocuploader.app.cli; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.apache.commons.net.PrintCommandListener; | ||
import org.apache.commons.net.ftp.FTPReply; | ||
import org.apache.commons.net.ftp.FTPSClient; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Profile; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.PrintWriter; | ||
|
||
@Slf4j | ||
@Component | ||
@Profile("production") | ||
public class FtpsClientImpl implements FtpsClient { | ||
|
||
private final String username; | ||
private final String password; | ||
private final String uploadUrl; | ||
private final String uploadDir; | ||
|
||
public FtpsClientImpl(@Value("${ftps.username:}") String username, @Value("${ftps.password:}") String password, @Value("${ftps.upload-url:}") String uploadUrl, @Value("${ftps.upload-dir:}") String uploadDir) { | ||
this.username = username; | ||
this.password = password; | ||
this.uploadUrl = uploadUrl; | ||
this.uploadDir = uploadDir; | ||
} | ||
|
||
@Override | ||
public void uploadFile(String zipFilename, byte[] data) throws IOException { | ||
FTPSClient ftp = new FTPSClient(); | ||
|
||
ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out))); | ||
|
||
ftp.connect(uploadUrl); | ||
int reply = ftp.getReplyCode(); | ||
if (!FTPReply.isPositiveCompletion(reply)) { | ||
ftp.disconnect(); | ||
throw new IOException("Exception in connecting to FTP Server"); | ||
} | ||
|
||
ftp.login(username, password); | ||
|
||
ftp.changeWorkingDirectory(uploadDir); | ||
|
||
ftp.execPBSZ(0); | ||
ftp.execPROT("P"); | ||
ftp.enterLocalPassiveMode(); | ||
ftp.pasv(); | ||
InputStream local = new ByteArrayInputStream(data); | ||
ftp.storeFile(zipFilename, local); | ||
local.close(); | ||
ftp.completePendingCommand(); | ||
|
||
ftp.logout(); | ||
ftp.disconnect(); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/org/ladocuploader/app/cli/MockFtpsClientImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package org.ladocuploader.app.cli; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.context.annotation.Profile; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Slf4j | ||
@Component | ||
@Profile("!production") | ||
public class MockFtpsClientImpl implements FtpsClient { | ||
|
||
@Override | ||
public void uploadFile(String zipFilename, byte[] data) { | ||
// Do nothing | ||
log.info("Mock uploading file " + zipFilename); | ||
} | ||
} |
Oops, something went wrong.