Skip to content

Commit 85ae690

Browse files
Add data interceptor (#248)
Co-authored-by: Sree P <[email protected]>
1 parent a400c2c commit 85ae690

File tree

10 files changed

+128
-4
lines changed

10 files changed

+128
-4
lines changed

.github/workflows/run-tests.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ jobs:
2929
- uses: actions/checkout@v3
3030
- name: Set up ChromeDriver
3131
uses: nanasess/[email protected]
32+
with:
33+
chromedriver-version: '115.0.5790.102'
3234
- name: Set up JDK
3335
uses: actions/[email protected]
3436
with:
@@ -78,6 +80,8 @@ jobs:
7880
- uses: actions/checkout@v3
7981
- name: Set up ChromeDriver
8082
uses: nanasess/[email protected]
83+
with:
84+
chromedriver-version: '115.0.5790.102'
8185
- name: Set up JDK
8286
uses: actions/setup-java@v1
8387
with:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.ladocuploader.app.config;
2+
3+
import formflow.library.data.SubmissionRepositoryService;
4+
import org.ladocuploader.app.interceptors.DataRequiredInterceptor;
5+
import org.springframework.beans.factory.annotation.Autowired;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
8+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
9+
10+
@Configuration
11+
public class DataRequiredHandlerConfiguration implements WebMvcConfigurer {
12+
@Autowired
13+
SubmissionRepositoryService submissionRepositoryService;
14+
15+
@Override
16+
public void addInterceptors(InterceptorRegistry registry) {
17+
registry.addInterceptor(new DataRequiredInterceptor(this.submissionRepositoryService)).addPathPatterns(DataRequiredInterceptor.PATH_FORMAT);
18+
}
19+
}

src/main/java/org/ladocuploader/app/config/SecurityConfiguration.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22

33
import org.springframework.context.annotation.Bean;
44
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.security.config.Customizer;
56
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
67
import org.springframework.security.web.SecurityFilterChain;
78

89
@Configuration
910
public class SecurityConfiguration {
1011
@Bean
1112
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
12-
http.httpBasic().disable();
13+
http.
14+
httpBasic(Customizer.withDefaults()
15+
);
1316
return http.build();
1417
}
1518
}

src/main/java/org/ladocuploader/app/filters/LoggingFilter.java

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
2929
MDC.put("sessionCreatedAt", new DateTime(request.getSession().getCreationTime()).toString("HH:mm:ss.SSS"));
3030
MDC.put("method", request.getMethod());
3131
MDC.put("request", request.getRequestURI());
32+
MDC.put("ip", request.getRemoteAddr());
3233
filterChain.doFilter(servletRequest, servletResponse);
3334
MDC.clear();
3435
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package org.ladocuploader.app.interceptors;
2+
3+
import formflow.library.data.SubmissionRepositoryService;
4+
import jakarta.servlet.http.HttpServletRequest;
5+
import jakarta.servlet.http.HttpServletResponse;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.springframework.stereotype.Component;
8+
import org.springframework.util.AntPathMatcher;
9+
import org.springframework.web.servlet.HandlerInterceptor;
10+
11+
import java.util.Map;
12+
import java.util.UUID;
13+
14+
@Component
15+
@Slf4j
16+
public class DataRequiredInterceptor implements HandlerInterceptor {
17+
public static final String PATH_FORMAT = "/flow/{flow}/{screen}";
18+
private final SubmissionRepositoryService submissionRepositoryService;
19+
private static final Map<String, String> REQUIRED_DATA = Map.ofEntries(
20+
// Step 1
21+
Map.entry("howToAddDocuments", "firstName"),
22+
Map.entry("uploadDocuments", "firstName"),
23+
Map.entry("docSubmitConfirmation", "firstName"),
24+
Map.entry("finalConfirmation", "firstName")
25+
);
26+
27+
public DataRequiredInterceptor(SubmissionRepositoryService submissionRepositoryService) {
28+
this.submissionRepositoryService = submissionRepositoryService;
29+
}
30+
31+
@Override
32+
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
33+
try {
34+
var parsedUrl = new AntPathMatcher().extractUriTemplateVariables(PATH_FORMAT, request.getRequestURI());
35+
var requiredData = REQUIRED_DATA.get(parsedUrl.get("screen"));
36+
String redirect_url = String.format("/flow/laDocUpload/clientInfo?intercepted=%s", parsedUrl.get("screen"));
37+
if (requiredData == null) {
38+
return true; // There are no data requirements for this page
39+
}
40+
41+
var session = request.getSession(false);
42+
if (session == null) {
43+
log.info("No session present (missing field data %s), redirecting to clientInfo page".formatted(requiredData));
44+
response.sendRedirect(redirect_url);
45+
46+
return false;
47+
}
48+
49+
var submissionId = (UUID) session.getAttribute("id");
50+
if (submissionId != null) {
51+
var submissionMaybe = this.submissionRepositoryService.findById(submissionId);
52+
if (submissionMaybe.isPresent()) {
53+
var submission = submissionMaybe.get();
54+
if (submission.getInputData().getOrDefault(requiredData, "").toString().isBlank()) {
55+
log.error("Submission %s missing field data %s, redirecting to clientInfo page".formatted(submissionId, requiredData));
56+
response.sendRedirect(redirect_url);
57+
return false;
58+
}
59+
} else {
60+
log.error("Submission %s not found in database (required field %s), redirecting to clientInfo page".formatted(submissionId, requiredData));
61+
response.sendRedirect(redirect_url);
62+
return false;
63+
}
64+
} else {
65+
log.error("No submission ID in session (required field %s), redirecting to clientInfo page".formatted(requiredData));
66+
response.sendRedirect(redirect_url);
67+
return false;
68+
}
69+
70+
return true;
71+
} catch (IllegalStateException e) {
72+
return true;
73+
}
74+
}
75+
}

src/main/resources/messages.properties

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ general.files.add-your-files=Add files
55
general.files.file-added.one=1 file added ({0} max)
66
general.files.file-added.other={0} files added ({1} max)
77
general.files.confirm-delete=You are about to delete your file called {0}. Is that okay?
8+
general.missing-info=Something went wrong. Please re-enter your information.
89
general.files.uploaded-documents=Uploaded documents
910
general.delete=delete
1011
general.cancel=Cancel

src/main/resources/templates/fragments/fileUploader.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
window['myDropZone' + [[${inputName}]]] = null;
6464
window['userFileIds' + [[${inputName}]]] = [];
6565
window['cancelledFiles' + [[${inputName}]]] = [];
66-
var userFiles = [[${session.userFiles}]]
66+
var userFiles = [[${session.userFiles ?: ''}]]
6767
var thumbnailWidthFromAppYml = [[${@environment.getProperty('form-flow.uploads.thumbnail-width')}]];
6868
var thumbnailHeightFromAppYml = [[${@environment.getProperty('form-flow.uploads.thumbnail-height')}]];
6969
var thumbnailWidth = thumbnailWidthFromAppYml ? thumbnailWidthFromAppYml : '64';
@@ -235,7 +235,6 @@
235235
}
236236

237237
$("#document-upload-" + [[${inputName}]]).dropzone({
238-
// TODO: use a variable? Use to get it from the id being on the form element
239238
url: "/file-upload",
240239
uploadMultiple: false,
241240
previewsContainer: [[${'#document-upload-' + inputName}]] + " .preview-container",
@@ -431,7 +430,8 @@
431430
},
432431
error: function (file, errorMessage, xhr) {
433432
if (xhr && xhr.response) {
434-
file.previewElement.getElementsByClassName("text--error")[0].innerText = xhr.response;
433+
// redirect to client info page with intercepted param for error popup
434+
location.href = "/flow/laDocUpload/clientInfo?intercepted=uploadDocuments"
435435
} else {
436436
var message = errorMessage.error ? errorMessage.error : errorMessage;
437437
file.previewElement.getElementsByClassName("text--error")[0].innerText = message;

src/main/resources/templates/fragments/mixpanelTracking.html

+11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@
1717
const ref_id = ref_id_param ? ref_id_param : '[[${submission == null ? "" : submission.getUrlParams().getOrDefault("ref_id", "")}]]'
1818
const ref_id_sanitized = ref_id.replaceAll("[^a-zA-Z0-9]", "");
1919

20+
const intercepted_param = window.location.href.includes("?intercepted=") ? window.location.href.split("?intercepted=")[1].split('&')[0] : null
21+
22+
if (intercepted_param) {
23+
mixpanel.track("error",
24+
{
25+
error_message: 'Something went wrong. Please re-enter your information.',
26+
error_location: intercepted_param
27+
}
28+
)
29+
}
30+
2031
if ((ref_id_sanitized.startsWith("T")) && (ref_id_sanitized.length === 11)){
2132
tracking_params.ref_id = ref_id_sanitized
2233
}

src/main/resources/templates/fragments/toolbar.html

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
}
2525
})
2626

27+
$(".flash__dismiss").on("click", function (e) {
28+
$(this).parent()[0].setAttribute("class", "display-none");
29+
})
30+
2731
});
2832
</script>
2933
<div th:replace="~{fragments/localeSelect :: localeSelect}"></div>

src/main/resources/templates/laDocUpload/clientInfo.html

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
<div class="grid">
99
<div th:replace="~{fragments/goBack :: goBackLink}"></div>
1010
<main id="content" role="main" class="form-card spacing-above-35">
11+
<div class="intercept-error-container">
12+
<div class="flash flash--error" id="client-info-missing" th:if="${param.intercepted != null}" >
13+
<p class="flash__message" th:text="#{general.missing-info}"></p>
14+
<a href="#" class="flash__dismiss" aria-label="Dismiss"><span class="icon icon-close"></span></a>
15+
</div>
16+
</div>
1117
<th:block th:replace="~{fragments/icons :: matchInfo}"></th:block>
1218
<th:block
1319
th:replace="~{fragments/cardHeader :: cardHeader(header=#{client-info.header}, subtext=#{client-info.subtext})}"/>

0 commit comments

Comments
 (0)