From 5d49b68232aa80a5ce8f794ad27322f0d5828c50 Mon Sep 17 00:00:00 2001
From: GavCookCO <99668051+GavCookCO@users.noreply.github.com>
Date: Thu, 16 Nov 2023 14:47:20 +0000
Subject: [PATCH 01/19] TMI2-396: Add submissions to SQS for processing in
Spotlight (#51)
* first pass at adding Spotlight submission + batch + queue
* first pass at adding Spotlight submission + batch + queue
* Adding functionality to send Spotlight Submissions to SQS
* refactoring a property name
* PR feedback
---
pom.xml | 5 +-
.../gap/applybackend/config/SQSConfig.java | 17 ++++
.../SpotlightQueueConfigProperties.java | 21 +++++
.../enums/SpotlightBatchStatus.java | 7 ++
.../enums/SpotlightSubmissionStatus.java | 9 ++
.../applybackend/model/SpotlightBatch.java | 49 ++++++++++
.../model/SpotlightSubmission.java | 55 +++++++++++
.../SpotlightSubmissionRepository.java | 10 ++
.../GrantMandatoryQuestionService.java | 6 +-
.../service/SpotlightService.java | 54 +++++++++++
.../GrantMandatoryQuestionsController.java | 2 +-
.../web/SubmissionController.java | 9 ++
src/main/resources/application.properties | 4 +-
.../GrantMandatoryQuestionServiceTest.java | 13 +--
.../service/SpotlightServiceTest.java | 94 +++++++++++++++++++
.../web/SubmissionControllerTest.java | 69 ++++++++++----
16 files changed, 396 insertions(+), 28 deletions(-)
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/config/SQSConfig.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/config/SpotlightQueueConfigProperties.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightBatchStatus.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightSubmissionStatus.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightBatch.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightSubmission.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/repository/SpotlightSubmissionRepository.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/service/SpotlightService.java
create mode 100644 src/test/java/gov/cabinetoffice/gap/applybackend/service/SpotlightServiceTest.java
diff --git a/pom.xml b/pom.xml
index 3859ab7f..ac3ecd89 100644
--- a/pom.xml
+++ b/pom.xml
@@ -160,7 +160,10 @@
commons-lang3
3.13.0
-
+
+ com.amazonaws
+ aws-java-sdk-sqs
+
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/config/SQSConfig.java b/src/main/java/gov/cabinetoffice/gap/applybackend/config/SQSConfig.java
new file mode 100644
index 00000000..4b91c913
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/config/SQSConfig.java
@@ -0,0 +1,17 @@
+package gov.cabinetoffice.gap.applybackend.config;
+
+import com.amazonaws.services.sqs.AmazonSQS;
+import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
+import lombok.RequiredArgsConstructor;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@RequiredArgsConstructor
+public class SQSConfig {
+
+ @Bean
+ AmazonSQS amazonSQS() {
+ return AmazonSQSClientBuilder.defaultClient();
+ }
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/config/SpotlightQueueConfigProperties.java b/src/main/java/gov/cabinetoffice/gap/applybackend/config/SpotlightQueueConfigProperties.java
new file mode 100644
index 00000000..1f0ccca2
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/config/SpotlightQueueConfigProperties.java
@@ -0,0 +1,21 @@
+package gov.cabinetoffice.gap.applybackend.config;
+
+import lombok.*;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import javax.validation.constraints.NotNull;
+
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Configuration
+@ConfigurationProperties(prefix = "spotlight-queue")
+public class SpotlightQueueConfigProperties {
+
+ @NotNull
+ private String queueUrl;
+
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightBatchStatus.java b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightBatchStatus.java
new file mode 100644
index 00000000..01470938
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightBatchStatus.java
@@ -0,0 +1,7 @@
+package gov.cabinetoffice.gap.applybackend.enums;
+
+public enum SpotlightBatchStatus {
+ QUEUED,
+ SUCCESS,
+ FAILURE
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightSubmissionStatus.java b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightSubmissionStatus.java
new file mode 100644
index 00000000..bbb68a60
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/SpotlightSubmissionStatus.java
@@ -0,0 +1,9 @@
+package gov.cabinetoffice.gap.applybackend.enums;
+
+public enum SpotlightSubmissionStatus {
+ QUEUED,
+ SENT,
+ SEND_ERROR,
+ GGIS_ERROR,
+ VALIDATION_ERROR
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightBatch.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightBatch.java
new file mode 100644
index 00000000..472caf6f
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightBatch.java
@@ -0,0 +1,49 @@
+package gov.cabinetoffice.gap.applybackend.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.*;
+import java.time.Instant;
+import java.util.List;
+import java.util.UUID;
+
+@EntityListeners(AuditingEntityListener.class)
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Entity
+@Table(name= "spotlight_batch")
+public class SpotlightBatch {
+
+ @Id
+ @GeneratedValue
+ private UUID id;
+
+ @Column
+ private String status;
+
+ @Column
+ private Instant lastSendAttempt;
+
+ @Column
+ private int version;
+
+ @Column(name = "created", nullable = false)
+ @Builder.Default
+ private Instant created = Instant.now();
+
+ @Column(name = "last_updated")
+ private Instant lastUpdated;
+
+ @ManyToMany
+ @JoinTable(
+ name = "spotlight_batch_submission",
+ joinColumns = @JoinColumn(name = "spotlight_batch_id"),
+ inverseJoinColumns = @JoinColumn(name = "spotlight_submission_id"))
+ private List spotlightSubmissions;
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightSubmission.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightSubmission.java
new file mode 100644
index 00000000..bd6dc30d
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/SpotlightSubmission.java
@@ -0,0 +1,55 @@
+package gov.cabinetoffice.gap.applybackend.model;
+
+import gov.cabinetoffice.gap.applybackend.enums.SpotlightSubmissionStatus;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+import javax.persistence.*;
+import java.time.Instant;
+import java.util.List;
+import java.util.UUID;
+
+@EntityListeners(AuditingEntityListener.class)
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+@Entity
+@Table(name= "spotlight_submission")
+public class SpotlightSubmission {
+
+ @Id
+ @GeneratedValue
+ private UUID id;
+
+ @OneToOne
+ @JoinColumn(name = "grant_mandatory_questions_id")
+ private GrantMandatoryQuestions mandatoryQuestions;
+
+ @ManyToOne
+ @JoinColumn(name = "grant_scheme")
+ private GrantScheme grantScheme;
+
+ @Builder.Default
+ @Column
+ private String status = SpotlightSubmissionStatus.QUEUED.toString();
+
+ @Column(name = "last_send_attempt")
+ private Instant lastSendAttempt;
+
+ @Column
+ private int version;
+
+ @Column(name = "created", nullable = false)
+ @Builder.Default
+ private Instant created = Instant.now();
+
+ @Column(name = "last_updated", nullable = false)
+ private Instant lastUpdated;
+
+ @ManyToMany
+ private List batches;
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/repository/SpotlightSubmissionRepository.java b/src/main/java/gov/cabinetoffice/gap/applybackend/repository/SpotlightSubmissionRepository.java
new file mode 100644
index 00000000..dcf2fcc6
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/repository/SpotlightSubmissionRepository.java
@@ -0,0 +1,10 @@
+package gov.cabinetoffice.gap.applybackend.repository;
+
+import gov.cabinetoffice.gap.applybackend.model.SpotlightSubmission;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+import java.util.UUID;
+
+public interface SpotlightSubmissionRepository extends JpaRepository {
+
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
index ae78909f..6fb7e1bb 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
@@ -38,7 +38,11 @@ public GrantMandatoryQuestions getGrantMandatoryQuestionById(UUID id, String app
return grantMandatoryQuestion.get();
}
- public GrantMandatoryQuestions getGrantMandatoryQuestionBySubmissionId(UUID submissionId, String applicantSub) {
+ /*
+ TODO I think we should decouple access control and CRUD functionality.
+ These methods should not require an applicant ID to be passed in to confirm ownership.
+ */
+ public GrantMandatoryQuestions getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(UUID submissionId, String applicantSub) {
final Optional grantMandatoryQuestion = ofNullable(grantMandatoryQuestionRepository.findBySubmissionId(submissionId)
.orElseThrow(() -> new NotFoundException(String.format("No Mandatory Question with submission id %s was found", submissionId))));
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/SpotlightService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/SpotlightService.java
new file mode 100644
index 00000000..2239749a
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/SpotlightService.java
@@ -0,0 +1,54 @@
+package gov.cabinetoffice.gap.applybackend.service;
+
+import com.amazonaws.services.sqs.AmazonSQS;
+import com.amazonaws.services.sqs.model.MessageAttributeValue;
+import com.amazonaws.services.sqs.model.SendMessageRequest;
+import gov.cabinetoffice.gap.applybackend.config.SpotlightQueueConfigProperties;
+import gov.cabinetoffice.gap.applybackend.model.GrantMandatoryQuestions;
+import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
+import gov.cabinetoffice.gap.applybackend.model.SpotlightSubmission;
+import gov.cabinetoffice.gap.applybackend.repository.SpotlightSubmissionRepository;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.util.UUID;
+
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class SpotlightService {
+
+ public static final String SPOTLIGHT_SUBMISSION_ID = "spotlightSubmissionId";
+ public static final int SPOTLIGHT_SUBSCRIPTION_VERSION = 1;
+ private final SpotlightSubmissionRepository spotlightSubmissionRepository;
+ private final AmazonSQS amazonSqs;
+ private final SpotlightQueueConfigProperties spotlightQueueProperties;
+ private final Clock clock;
+
+ public void createSpotlightCheck(GrantMandatoryQuestions mandatoryQuestions, GrantScheme scheme) {
+
+ // save a spotlight submission object to the database
+ final SpotlightSubmission spotlightSubmission = SpotlightSubmission.builder()
+ .mandatoryQuestions(mandatoryQuestions)
+ .grantScheme(scheme)
+ .version(SPOTLIGHT_SUBSCRIPTION_VERSION)
+ .lastUpdated(Instant.now(clock))
+ .build();
+
+ final SpotlightSubmission savedSpotlightSubmission = spotlightSubmissionRepository.save(spotlightSubmission);
+
+ // send that object to SQS for processing
+ final UUID messageId = UUID.randomUUID();
+
+ final SendMessageRequest messageRequest = new SendMessageRequest()
+ .withQueueUrl(spotlightQueueProperties.getQueueUrl())
+ .withMessageGroupId(messageId.toString())
+ .withMessageBody(savedSpotlightSubmission.getId().toString())
+ .withMessageDeduplicationId(messageId.toString());
+
+ amazonSqs.sendMessage(messageRequest);
+ }
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java
index 5945a9c2..51ffe383 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java
@@ -81,7 +81,7 @@ public ResponseEntity getGrantMandatoryQuestionsBy
})
public ResponseEntity getGrantMandatoryQuestionsBySubmissionId(@PathVariable final UUID submissionId) {
final JwtPayload jwtPayload = (JwtPayload) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- final GrantMandatoryQuestions grantMandatoryQuestions = grantMandatoryQuestionService.getGrantMandatoryQuestionBySubmissionId(submissionId, jwtPayload.getSub());
+ final GrantMandatoryQuestions grantMandatoryQuestions = grantMandatoryQuestionService.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submissionId, jwtPayload.getSub());
log.info("Mandatory question with ID {} has been retrieved.", grantMandatoryQuestions.getId());
final GetGrantMandatoryQuestionDto getGrantMandatoryQuestionBySubmissionDto = grantMandatoryQuestionMapper.mapGrantMandatoryQuestionToGetGrantMandatoryQuestionDTO(grantMandatoryQuestions);
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java b/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java
index 2373cde3..0ad4e70c 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java
@@ -36,6 +36,8 @@ public class SubmissionController {
private final GrantApplicantService grantApplicantService;
private final GrantAttachmentService grantAttachmentService;
private final GrantApplicationService grantApplicationService;
+ private final SpotlightService spotlightService;
+ private final GrantMandatoryQuestionService mandatoryQuestionService;
private final SecretAuthService secretAuthService;
private final AttachmentService attachmentService;
@@ -179,8 +181,15 @@ public ResponseEntity submitApplication(@RequestBody SubmitApplicationDt
final JwtPayload jwtPayload = (JwtPayload) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
final GrantApplicant grantApplicant = grantApplicantService.getApplicantFromPrincipal();
final Submission submission = submissionService.getSubmissionFromDatabaseBySubmissionId(grantApplicant.getUserId(), applicationSubmission.getSubmissionId());
+ final GrantScheme scheme = submission.getScheme();
+
submissionService.submit(submission, grantApplicant, jwtPayload.getEmail());
+ if (scheme.getVersion() > 1) {
+ final GrantMandatoryQuestions mandatoryQuestions = mandatoryQuestionService.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submission.getId(), grantApplicant.getUserId());
+ spotlightService.createSpotlightCheck(mandatoryQuestions, scheme);
+ }
+
return ResponseEntity.ok("Submitted");
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index cf558eb3..4d9540e0 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -43,4 +43,6 @@ feature.onelogin.enabled=false
contentful.spaceId=a-space-id
contentful.accessToken=an-access-token
contentful.deliveryAPIAccessToken=an-access-token
-contentful.environmentId=an-environment
\ No newline at end of file
+contentful.environmentId=an-environment
+
+spotlight-queue.queueUrl=a-sqs-queue-url
\ No newline at end of file
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
index 13ac1966..8d34c078 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
@@ -124,7 +124,7 @@ void getGrantMandatoryQuestionBySubmissionId_ThrowsNotFoundException() {
when(grantMandatoryQuestionRepository.findBySubmissionId(submissionId))
.thenThrow(NotFoundException.class);
- assertThrows(NotFoundException.class, () -> serviceUnderTest.getGrantMandatoryQuestionBySubmissionId(submissionId, applicantUserId));
+ assertThrows(NotFoundException.class, () -> serviceUnderTest.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submissionId, applicantUserId));
}
@Test
@@ -146,7 +146,7 @@ void getGrantMandatoryQuestionBySubmissionId_ThrowsForbiddenException() {
when(grantMandatoryQuestionRepository.findBySubmissionId(submissionId))
.thenReturn(mandatoryQuestions);
- assertThrows(ForbiddenException.class, () -> serviceUnderTest.getGrantMandatoryQuestionBySubmissionId(submissionId, invalidUserId));
+ assertThrows(ForbiddenException.class, () -> serviceUnderTest.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submissionId, invalidUserId));
}
@Test
@@ -167,7 +167,7 @@ void getGrantMandatoryQuestionBySubmissionId_ReturnsExpectedMandatoryQuestions()
when(grantMandatoryQuestionRepository.findBySubmissionId(submissionId))
.thenReturn(mandatoryQuestions);
- final GrantMandatoryQuestions methodResponse = serviceUnderTest.getGrantMandatoryQuestionBySubmissionId(submissionId, applicantUserId);
+ final GrantMandatoryQuestions methodResponse = serviceUnderTest.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submissionId, applicantUserId);
assertThat(methodResponse).isEqualTo(mandatoryQuestions.get());
}
@@ -335,8 +335,9 @@ void createMandatoryQuestion_NullsCCandCH_ifTooLong() {
verify(organisationProfileMapper).mapOrgProfileToGrantMandatoryQuestion(orgProfileWithLongCCandCH);
verify(grantMandatoryQuestionRepository).save(any());
- assertThat(methodResponse.getCharityCommissionNumber()).isEqualTo(null);
- assertThat(methodResponse.getCompaniesHouseNumber()).isEqualTo(null);
+
+ assertThat(methodResponse.getCharityCommissionNumber()).isNull();
+ assertThat(methodResponse.getCompaniesHouseNumber()).isNull();
}
}
@@ -438,7 +439,7 @@ void testGenerateNextPageUrl() {
}
@Test
- public void testGenerateNextPageUrl_UrlNotInMapper() {
+ void testGenerateNextPageUrl_UrlNotInMapper() {
final String url = "/any/url/thatIsNotInMapper";
final String expectedNextPageUrl = "";
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/SpotlightServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/SpotlightServiceTest.java
new file mode 100644
index 00000000..c8b167ce
--- /dev/null
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/SpotlightServiceTest.java
@@ -0,0 +1,94 @@
+package gov.cabinetoffice.gap.applybackend.service;
+
+import com.amazonaws.services.sqs.AmazonSQS;
+import com.amazonaws.services.sqs.model.SendMessageRequest;
+import gov.cabinetoffice.gap.applybackend.config.SpotlightQueueConfigProperties;
+import gov.cabinetoffice.gap.applybackend.enums.SpotlightSubmissionStatus;
+import gov.cabinetoffice.gap.applybackend.model.GrantMandatoryQuestions;
+import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
+import gov.cabinetoffice.gap.applybackend.model.SpotlightSubmission;
+import gov.cabinetoffice.gap.applybackend.repository.SpotlightSubmissionRepository;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.util.UUID;
+
+@ExtendWith(MockitoExtension.class)
+class SpotlightServiceTest {
+
+ @Mock
+ private SpotlightSubmissionRepository spotlightSubmissionRepository;
+
+ @Mock
+ private AmazonSQS amazonSqs;
+
+ private SpotlightQueueConfigProperties spotlightQueueProperties;
+ private final String SPOOKY_DAY_OOOOO = "2023-10-31T12:00:00.00z";
+ private final Clock clock = Clock.fixed(Instant.parse(SPOOKY_DAY_OOOOO), ZoneId.of("UTC"));
+
+ private SpotlightService serviceUnderTest;
+
+ @BeforeEach
+ void setup() {
+ spotlightQueueProperties = SpotlightQueueConfigProperties.builder()
+ .queueUrl("a-queue-url")
+ .build();
+
+ serviceUnderTest = new SpotlightService(spotlightSubmissionRepository, amazonSqs, spotlightQueueProperties, clock);
+ }
+
+ @Test
+ void createSpotlightCheck_CreatesDatabaseEntry_AndAddsToQueue() {
+
+ final GrantMandatoryQuestions mqs = GrantMandatoryQuestions.builder().build();
+ final GrantScheme scheme = GrantScheme.builder()
+ .version(2)
+ .build();
+
+ final ArgumentCaptor spotlightSubmissionCaptor = ArgumentCaptor.forClass(SpotlightSubmission.class);
+
+ final SpotlightSubmission submissionAfterSave = SpotlightSubmission.builder()
+ .id(UUID.randomUUID())
+ .build();
+
+ when(spotlightSubmissionRepository.save(Mockito.any()))
+ .thenReturn(submissionAfterSave);
+
+ final ArgumentCaptor sqsRequestCaptor = ArgumentCaptor.forClass(SendMessageRequest.class);
+
+ serviceUnderTest.createSpotlightCheck(mqs, scheme);
+
+ // Test that the spotlight submission has been saved to the relational database
+ verify(spotlightSubmissionRepository).save(spotlightSubmissionCaptor.capture());
+
+ final SpotlightSubmission spotlightSubmission = spotlightSubmissionCaptor.getValue();
+
+ assertThat(spotlightSubmission.getMandatoryQuestions()).isEqualTo(mqs);
+ assertThat(spotlightSubmission.getGrantScheme()).isEqualTo(scheme);
+ assertThat(spotlightSubmission.getVersion()).isEqualTo(SpotlightService.SPOTLIGHT_SUBSCRIPTION_VERSION);
+ assertThat(spotlightSubmission.getLastUpdated()).isEqualTo(Instant.now(clock));
+ assertThat(spotlightSubmission.getStatus()).isEqualTo(SpotlightSubmissionStatus.QUEUED.toString());
+
+
+ // Test that the spotlight submission has been sent to SQS
+ verify(amazonSqs).sendMessage(sqsRequestCaptor.capture());
+
+ final SendMessageRequest sqsRequest = sqsRequestCaptor.getValue();
+
+ assertThat(sqsRequest.getMessageBody()).isNotNull();
+ assertThat(sqsRequest.getQueueUrl()).isEqualTo(spotlightQueueProperties.getQueueUrl());
+ assertThat(sqsRequest.getMessageBody()).isEqualTo(submissionAfterSave.getId().toString());
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java
index a5df3e37..356d5313 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java
@@ -22,23 +22,8 @@
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
import gov.cabinetoffice.gap.applybackend.exception.SubmissionAlreadyCreatedException;
import gov.cabinetoffice.gap.applybackend.exception.UnauthorizedException;
-import gov.cabinetoffice.gap.applybackend.model.ApplicationDefinition;
-import gov.cabinetoffice.gap.applybackend.model.GrantApplicant;
-import gov.cabinetoffice.gap.applybackend.model.GrantApplicantOrganisationProfile;
-import gov.cabinetoffice.gap.applybackend.model.GrantApplication;
-import gov.cabinetoffice.gap.applybackend.model.GrantAttachment;
-import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
-import gov.cabinetoffice.gap.applybackend.model.Submission;
-import gov.cabinetoffice.gap.applybackend.model.SubmissionDefinition;
-import gov.cabinetoffice.gap.applybackend.model.SubmissionQuestion;
-import gov.cabinetoffice.gap.applybackend.model.SubmissionQuestionValidation;
-import gov.cabinetoffice.gap.applybackend.model.SubmissionSection;
-import gov.cabinetoffice.gap.applybackend.service.AttachmentService;
-import gov.cabinetoffice.gap.applybackend.service.GrantApplicantService;
-import gov.cabinetoffice.gap.applybackend.service.GrantApplicationService;
-import gov.cabinetoffice.gap.applybackend.service.GrantAttachmentService;
-import gov.cabinetoffice.gap.applybackend.service.SecretAuthService;
-import gov.cabinetoffice.gap.applybackend.service.SubmissionService;
+import gov.cabinetoffice.gap.applybackend.model.*;
+import gov.cabinetoffice.gap.applybackend.service.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -287,6 +272,12 @@ class SubmissionControllerTest {
@Mock
private AttachmentService attachmentService;
+ @Mock
+ private SpotlightService spotlightService;
+
+ @Mock
+ private GrantMandatoryQuestionService mandatoryQuestionService;
+
final String CHRISTMAS_2022_MIDDAY = "2022-12-25T12:00:00.00z";
final Clock clock = Clock.fixed(Instant.parse(CHRISTMAS_2022_MIDDAY), ZoneId.of("UTC"));
@@ -294,7 +285,8 @@ class SubmissionControllerTest {
@BeforeEach
void setup() {
- controllerUnderTest = new SubmissionController(submissionService, grantApplicantService, grantAttachmentService, grantApplicationService, secretAuthService, attachmentService, clock);
+ // TODO holy argument list batman, this class needs broken down!§§§
+ controllerUnderTest = new SubmissionController(submissionService, grantApplicantService, grantAttachmentService, grantApplicationService, spotlightService, mandatoryQuestionService, secretAuthService, attachmentService, clock);
when(securityContext.getAuthentication()).thenReturn(authentication);
SecurityContextHolder.setContext(securityContext);
JwtPayload jwtPayload = JwtPayload.builder().sub(String.valueOf(APPLICANT_USER_ID)).build();
@@ -464,6 +456,47 @@ void submitApplication_isSuccessfulAndReturnsExpectedResponse() {
assertThat(response.getBody()).isEqualTo("Submitted");
}
+ @Test
+ void submitApplication_isSuccessfulAndReturnsExpectedResponse_ForV2Schemes() {
+
+ // set up the V2 scheme
+ submission.getScheme().setVersion(2);
+
+ final String emailAddress = "test@email.com";
+ final GrantApplicant grantApplicant = GrantApplicant.builder().userId(APPLICANT_USER_ID).id(1).build();
+ final SubmitApplicationDto submitApplication = SubmitApplicationDto.builder()
+ .submissionId(SUBMISSION_ID)
+ .build();
+ final JwtPayload jwtPayload = JwtPayload.builder().sub(APPLICANT_USER_ID).email(emailAddress).build();
+
+ final GrantMandatoryQuestions mandatoryQuestions = GrantMandatoryQuestions.builder()
+ .build();
+
+ when(SecurityContextHolder.getContext().getAuthentication().getPrincipal())
+ .thenReturn(jwtPayload);
+
+ when(submissionService.getSubmissionFromDatabaseBySubmissionId(APPLICANT_USER_ID, SUBMISSION_ID))
+ .thenReturn(submission);
+
+ when(grantApplicantService.getApplicantFromPrincipal())
+ .thenReturn(grantApplicant);
+
+ when(mandatoryQuestionService.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submission.getId(), grantApplicant.getUserId()))
+ .thenReturn(mandatoryQuestions);
+
+
+ final ResponseEntity response = controllerUnderTest.submitApplication(submitApplication);
+
+
+ verify(mandatoryQuestionService).getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submission.getId(), grantApplicant.getUserId());
+ verify(spotlightService).createSpotlightCheck(mandatoryQuestions, submission.getScheme());
+ verify(submissionService).getSubmissionFromDatabaseBySubmissionId(APPLICANT_USER_ID, SUBMISSION_ID);
+ verify(submissionService).submit(submission, grantApplicant, emailAddress);
+
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(response.getBody()).isEqualTo("Submitted");
+ }
+
@Test
void submitApplication_ThrowsNotFoundException_IfSubmissionNotFound() {
From 1206a3f8262cd397238c1fc337046e07e7efaffd Mon Sep 17 00:00:00 2001
From: Conor Fayle <141320269+ConorFayleTCO@users.noreply.github.com>
Date: Fri, 17 Nov 2023 11:32:31 +0000
Subject: [PATCH 02/19] GAP-2251: MQ Conditional Logic - Choose organisation
type (#56)
* GAP-2251 | change order of MQs, add conditional logic for non-limited company and individual
* GAP-2251 | remove public for test func
* GAP-2251 | fix test
---------
Co-authored-by: conor
---
.../model/GrantMandatoryQuestions.java | 10 +--
.../GrantMandatoryQuestionService.java | 17 +++--
.../GrantMandatoryQuestionsController.java | 2 +-
src/main/resources/banner.txt | 8 ++
.../GrantMandatoryQuestionServiceTest.java | 76 ++++++++++++++++++-
...GrantMandatoryQuestionsControllerTest.java | 7 +-
6 files changed, 102 insertions(+), 18 deletions(-)
create mode 100644 src/main/resources/banner.txt
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantMandatoryQuestions.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantMandatoryQuestions.java
index 58d0a553..8b62ee01 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantMandatoryQuestions.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantMandatoryQuestions.java
@@ -51,6 +51,11 @@ public class GrantMandatoryQuestions extends BaseEntity {
@JoinColumn(name = "submission_id", referencedColumnName = "id")
private Submission submission;
+ @Column(name = "org_type")
+ @Enumerated(EnumType.STRING)
+ @ColumnTransformer(write = "?::grant_mandatory_question_type")
+ private GrantMandatoryQuestionOrgType orgType;
+
@Column(name = "name")
private String name;
@@ -69,11 +74,6 @@ public class GrantMandatoryQuestions extends BaseEntity {
@Column(name = "postcode")
private String postcode;
- @Column(name = "org_type")
- @Enumerated(EnumType.STRING)
- @ColumnTransformer(write = "?::grant_mandatory_question_type")
- private GrantMandatoryQuestionOrgType orgType;
-
@Column(name = "companies_house_number")
private String companiesHouseNumber;
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
index 6fb7e1bb..1b98e914 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
@@ -2,6 +2,7 @@
import gov.cabinetoffice.gap.applybackend.config.properties.EnvironmentProperties;
import gov.cabinetoffice.gap.applybackend.constants.MandatoryQuestionConstants;
+import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionOrgType;
import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionStatus;
import gov.cabinetoffice.gap.applybackend.enums.SubmissionQuestionResponseType;
import gov.cabinetoffice.gap.applybackend.enums.SubmissionSectionStatus;
@@ -105,14 +106,20 @@ public GrantMandatoryQuestions updateMandatoryQuestion(GrantMandatoryQuestions g
.orElseThrow(() -> new NotFoundException(String.format("No Mandatory Question with id %s was found", grantMandatoryQuestions.getId())));
}
- public String generateNextPageUrl(String url, UUID mandatoryQuestionId) {
+ public String generateNextPageUrl(String url, UUID mandatoryQuestionId, String applicantSub) {
+ final GrantMandatoryQuestions mqs = getGrantMandatoryQuestionById(mandatoryQuestionId, applicantSub);
final Map mapper = new HashMap<>();
String mandatoryQuestionsUrlStart = "/mandatory-questions/" + mandatoryQuestionId;
+ mapper.put("organisation-type", mandatoryQuestionsUrlStart + "/organisation-name");
mapper.put("organisation-name", mandatoryQuestionsUrlStart + "/organisation-address");
- mapper.put("organisation-address", mandatoryQuestionsUrlStart + "/organisation-type");
- mapper.put("organisation-type", mandatoryQuestionsUrlStart + "/organisation-companies-house-number");
- mapper.put("organisation-companies-house-number", mandatoryQuestionsUrlStart + "/organisation-charity-commission-number");
- mapper.put("organisation-charity-commission-number", mandatoryQuestionsUrlStart + "/organisation-funding-amount");
+ if (mqs.getOrgType() == GrantMandatoryQuestionOrgType.NON_LIMITED_COMPANY
+ || mqs.getOrgType() == GrantMandatoryQuestionOrgType.INDIVIDUAL) {
+ mapper.put("organisation-address", mandatoryQuestionsUrlStart + "/organisation-funding-amount");
+ } else {
+ mapper.put("organisation-address", mandatoryQuestionsUrlStart + "/organisation-companies-house-number");
+ mapper.put("organisation-companies-house-number", mandatoryQuestionsUrlStart + "/organisation-charity-commission-number");
+ mapper.put("organisation-charity-commission-number", mandatoryQuestionsUrlStart + "/organisation-funding-amount");
+ }
mapper.put("organisation-funding-amount", mandatoryQuestionsUrlStart + "/organisation-funding-location");
mapper.put("organisation-funding-location", mandatoryQuestionsUrlStart + "/organisation-summary");
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java
index 51ffe383..07fa77b6 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsController.java
@@ -154,6 +154,6 @@ public ResponseEntity updateMandatoryQuestion(@PathVariable final UUID m
log.info("Mandatory question with ID {} has been updated.", grantMandatoryQuestions.getId());
- return ResponseEntity.ok(grantMandatoryQuestionService.generateNextPageUrl(url, mandatoryQuestionId));
+ return ResponseEntity.ok(grantMandatoryQuestionService.generateNextPageUrl(url, mandatoryQuestionId, jwtPayload.getSub()));
}
}
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
new file mode 100644
index 00000000..8fccb5a9
--- /dev/null
+++ b/src/main/resources/banner.txt
@@ -0,0 +1,8 @@
+,------.,--. ,--. ,----. ,--.
+| .---'`--',--,--, ,-| | ,--,--. ' .-./ ,--.--.,--,--.,--,--, ,-' '-.
+| `--, ,--.| \' .-. | ' ,-. | | | .---.| .--' ,-. || \'-. .-'
+| |` | || || |\ `-' | \ '-' | ' '--' || | \ '-' || || | | |
+`--' `--'`--''--' `---' `--`--' `------' `--' `--`--'`--''--' `--'
+
+${info.app.name} (${info.app.version})
+Powered by Spring Boot ${spring-boot.version}
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
index 8d34c078..73362024 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
@@ -430,20 +430,90 @@ void updateMandatoryQuestion_UpdatesExpectedMandatoryQuestionsAndSetsGapIdBySubm
class generateNextPageUrl {
@Test
void testGenerateNextPageUrl() {
+ final GrantApplicant applicant = GrantApplicant
+ .builder()
+ .userId(applicantUserId)
+ .build();
+ final GrantMandatoryQuestions grantMandatoryQuestions = GrantMandatoryQuestions
+ .builder()
+ .id(MANDATORY_QUESTION_ID)
+ .createdBy(applicant)
+ .build();
+ when(grantMandatoryQuestionRepository.findById(MANDATORY_QUESTION_ID))
+ .thenReturn(Optional.of(grantMandatoryQuestions));
+
+ final String url = "/any/url/organisation-type?some-param=some-value";
+ final String expectedNextPageUrl = "/mandatory-questions/" + MANDATORY_QUESTION_ID + "/organisation-name";
+
+ final String nextPageUrl = serviceUnderTest.generateNextPageUrl(url, MANDATORY_QUESTION_ID, applicantUserId);
+
+ assertThat(nextPageUrl).isEqualTo(expectedNextPageUrl);
+ }
+
+ @Test
+ void testGenerateNextPageUrlForSkippingCompaniesHouseAndCharityCommission() {
+ final GrantApplicant applicant = GrantApplicant
+ .builder()
+ .userId(applicantUserId)
+ .build();
+ final GrantMandatoryQuestions grantMandatoryQuestions = GrantMandatoryQuestions
+ .builder()
+ .id(MANDATORY_QUESTION_ID)
+ .createdBy(applicant)
+ .orgType(GrantMandatoryQuestionOrgType.INDIVIDUAL)
+ .build();
+ when(grantMandatoryQuestionRepository.findById(MANDATORY_QUESTION_ID))
+ .thenReturn(Optional.of(grantMandatoryQuestions));
+
final String url = "/any/url/organisation-address?some-param=some-value";
- final String expectedNextPageUrl = "/mandatory-questions/" + MANDATORY_QUESTION_ID + "/organisation-type";
+ final String expectedNextPageUrl = "/mandatory-questions/" + MANDATORY_QUESTION_ID + "/organisation-funding-amount";
- final String nextPageUrl = serviceUnderTest.generateNextPageUrl(url, MANDATORY_QUESTION_ID);
+ final String nextPageUrl = serviceUnderTest.generateNextPageUrl(url, MANDATORY_QUESTION_ID, applicantUserId);
+
+ assertThat(nextPageUrl).isEqualTo(expectedNextPageUrl);
+ }
+
+ @Test
+ void testGenerateNextPageUrlForNotSkippingCompaniesHouseAndCharityCommission() {
+ final GrantApplicant applicant = GrantApplicant
+ .builder()
+ .userId(applicantUserId)
+ .build();
+ final GrantMandatoryQuestions grantMandatoryQuestions = GrantMandatoryQuestions
+ .builder()
+ .id(MANDATORY_QUESTION_ID)
+ .createdBy(applicant)
+ .orgType(GrantMandatoryQuestionOrgType.CHARITY)
+ .build();
+ when(grantMandatoryQuestionRepository.findById(MANDATORY_QUESTION_ID))
+ .thenReturn(Optional.of(grantMandatoryQuestions));
+
+ final String url = "/any/url/organisation-address?some-param=some-value";
+ final String expectedNextPageUrl = "/mandatory-questions/" + MANDATORY_QUESTION_ID + "/organisation-companies-house-number";
+
+ final String nextPageUrl = serviceUnderTest.generateNextPageUrl(url, MANDATORY_QUESTION_ID, applicantUserId);
assertThat(nextPageUrl).isEqualTo(expectedNextPageUrl);
}
@Test
void testGenerateNextPageUrl_UrlNotInMapper() {
+ final GrantApplicant applicant = GrantApplicant
+ .builder()
+ .userId(applicantUserId)
+ .build();
+ final GrantMandatoryQuestions grantMandatoryQuestions = GrantMandatoryQuestions
+ .builder()
+ .id(MANDATORY_QUESTION_ID)
+ .createdBy(applicant)
+ .build();
+ when(grantMandatoryQuestionRepository.findById(MANDATORY_QUESTION_ID))
+ .thenReturn(Optional.of(grantMandatoryQuestions));
+
final String url = "/any/url/thatIsNotInMapper";
final String expectedNextPageUrl = "";
- final String nextPageUrl = serviceUnderTest.generateNextPageUrl(url, MANDATORY_QUESTION_ID);
+ final String nextPageUrl = serviceUnderTest.generateNextPageUrl(url, MANDATORY_QUESTION_ID, applicantUserId);
assertThat(nextPageUrl).isEqualTo(expectedNextPageUrl);
}
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsControllerTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsControllerTest.java
index 145dd2af..2cc6e8f8 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsControllerTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantMandatoryQuestionsControllerTest.java
@@ -194,7 +194,7 @@ void updateMandatoryQuestion_UpdatesExpectedFields_AndSavesChanges() {
when(grantMandatoryQuestionService.updateMandatoryQuestion(mandatoryQuestions, applicant))
.thenReturn(mandatoryQuestions);
- when(grantMandatoryQuestionService.generateNextPageUrl("url", MANDATORY_QUESTION_ID))
+ when(grantMandatoryQuestionService.generateNextPageUrl("url", MANDATORY_QUESTION_ID, jwtPayload.getSub()))
.thenReturn("nextPageUrl");
@@ -235,7 +235,7 @@ void updateMandatoryQuestion_AddsSubmissionToMandatoryQuestions_IfSubmissionIdPr
when(grantMandatoryQuestionService.updateMandatoryQuestion(mandatoryQuestions, applicant))
.thenReturn(mandatoryQuestions);
- when(grantMandatoryQuestionService.generateNextPageUrl("url", MANDATORY_QUESTION_ID))
+ when(grantMandatoryQuestionService.generateNextPageUrl("url", MANDATORY_QUESTION_ID, jwtPayload.getSub()))
.thenReturn("nextPageUrl");
when(submissionService.getSubmissionFromDatabaseBySubmissionId(jwtPayload.getSub(), submissionId))
@@ -279,10 +279,9 @@ void updateMandatoryQuestion_SetsStatusToComplete() {
when(grantMandatoryQuestionService.updateMandatoryQuestion(mandatoryQuestions, applicant))
.thenReturn(mandatoryQuestions);
- when(grantMandatoryQuestionService.generateNextPageUrl("url", MANDATORY_QUESTION_ID))
+ when(grantMandatoryQuestionService.generateNextPageUrl("url", MANDATORY_QUESTION_ID, jwtPayload.getSub()))
.thenReturn("nextPageUrl");
-
final ResponseEntity methodResponse = controllerUnderTest.updateMandatoryQuestion(MANDATORY_QUESTION_ID, updateDto, "url");
verify(grantMandatoryQuestionService).addMandatoryQuestionsToSubmissionObject(mandatoryQuestions);
From 4a207fabeebaef1b0f0aa6ad8b9dbae51fb3afc9 Mon Sep 17 00:00:00 2001
From: GavCookCO <99668051+GavCookCO@users.noreply.github.com>
Date: Fri, 17 Nov 2023 12:50:17 +0000
Subject: [PATCH 03/19] Adding an org type check for sending to spotlight (#57)
---
.../web/SubmissionController.java | 12 +++-
.../web/SubmissionControllerTest.java | 57 ++++++++++++++++---
2 files changed, 59 insertions(+), 10 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java b/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java
index 0ad4e70c..5afa0101 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/web/SubmissionController.java
@@ -4,6 +4,7 @@
import gov.cabinetoffice.gap.applybackend.constants.APIConstants;
import gov.cabinetoffice.gap.applybackend.dto.api.*;
import gov.cabinetoffice.gap.applybackend.enums.GrantAttachmentStatus;
+import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionOrgType;
import gov.cabinetoffice.gap.applybackend.enums.SubmissionSectionStatus;
import gov.cabinetoffice.gap.applybackend.exception.AttachmentException;
import gov.cabinetoffice.gap.applybackend.exception.GrantApplicationNotPublishedException;
@@ -187,12 +188,21 @@ public ResponseEntity submitApplication(@RequestBody SubmitApplicationDt
if (scheme.getVersion() > 1) {
final GrantMandatoryQuestions mandatoryQuestions = mandatoryQuestionService.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submission.getId(), grantApplicant.getUserId());
- spotlightService.createSpotlightCheck(mandatoryQuestions, scheme);
+ final boolean shouldSendToSpotlight = !isOrganisationIndividualOrOther(mandatoryQuestions);
+
+ if (shouldSendToSpotlight) {
+ spotlightService.createSpotlightCheck(mandatoryQuestions, scheme);
+ }
}
return ResponseEntity.ok("Submitted");
}
+ private boolean isOrganisationIndividualOrOther(GrantMandatoryQuestions mandatoryQuestions) {
+ return mandatoryQuestions.getOrgType().equals(GrantMandatoryQuestionOrgType.INDIVIDUAL) ||
+ mandatoryQuestions.getOrgType().equals(GrantMandatoryQuestionOrgType.OTHER);
+ }
+
@PostMapping("/createSubmission/{applicationId}")
public ResponseEntity createApplication(@PathVariable final int applicationId) throws JsonProcessingException {
final String applicantId = getUserIdFromSecurityContext();
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java
index 356d5313..7d940d47 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/web/SubmissionControllerTest.java
@@ -13,10 +13,7 @@
import gov.cabinetoffice.gap.applybackend.dto.api.SubmissionReviewBodyDto;
import gov.cabinetoffice.gap.applybackend.dto.api.SubmitApplicationDto;
import gov.cabinetoffice.gap.applybackend.dto.api.UpdateAttachmentDto;
-import gov.cabinetoffice.gap.applybackend.enums.GrantAttachmentStatus;
-import gov.cabinetoffice.gap.applybackend.enums.SubmissionQuestionResponseType;
-import gov.cabinetoffice.gap.applybackend.enums.SubmissionSectionStatus;
-import gov.cabinetoffice.gap.applybackend.enums.SubmissionStatus;
+import gov.cabinetoffice.gap.applybackend.enums.*;
import gov.cabinetoffice.gap.applybackend.exception.AttachmentException;
import gov.cabinetoffice.gap.applybackend.exception.GrantApplicationNotPublishedException;
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
@@ -29,9 +26,12 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
+import static org.mockito.Mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -56,11 +56,6 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class SubmissionControllerTest {
@@ -470,6 +465,7 @@ void submitApplication_isSuccessfulAndReturnsExpectedResponse_ForV2Schemes() {
final JwtPayload jwtPayload = JwtPayload.builder().sub(APPLICANT_USER_ID).email(emailAddress).build();
final GrantMandatoryQuestions mandatoryQuestions = GrantMandatoryQuestions.builder()
+ .orgType(GrantMandatoryQuestionOrgType.LIMITED_COMPANY)
.build();
when(SecurityContextHolder.getContext().getAuthentication().getPrincipal())
@@ -497,6 +493,49 @@ void submitApplication_isSuccessfulAndReturnsExpectedResponse_ForV2Schemes() {
assertThat(response.getBody()).isEqualTo("Submitted");
}
+ @ParameterizedTest
+ @EnumSource(value = GrantMandatoryQuestionOrgType.class, names = {"INDIVIDUAL", "OTHER"})
+ void submitApplication_DoesNotCreateSpotlightCheck_ForIndividualsOrOther_ForV2Schemes(GrantMandatoryQuestionOrgType orgType) {
+
+ // set up the V2 scheme
+ submission.getScheme().setVersion(2);
+
+ final String emailAddress = "test@email.com";
+ final GrantApplicant grantApplicant = GrantApplicant.builder().userId(APPLICANT_USER_ID).id(1).build();
+ final SubmitApplicationDto submitApplication = SubmitApplicationDto.builder()
+ .submissionId(SUBMISSION_ID)
+ .build();
+ final JwtPayload jwtPayload = JwtPayload.builder().sub(APPLICANT_USER_ID).email(emailAddress).build();
+
+ final GrantMandatoryQuestions mandatoryQuestions = GrantMandatoryQuestions.builder()
+ .orgType(orgType)
+ .build();
+
+ when(SecurityContextHolder.getContext().getAuthentication().getPrincipal())
+ .thenReturn(jwtPayload);
+
+ when(submissionService.getSubmissionFromDatabaseBySubmissionId(APPLICANT_USER_ID, SUBMISSION_ID))
+ .thenReturn(submission);
+
+ when(grantApplicantService.getApplicantFromPrincipal())
+ .thenReturn(grantApplicant);
+
+ when(mandatoryQuestionService.getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submission.getId(), grantApplicant.getUserId()))
+ .thenReturn(mandatoryQuestions);
+
+
+ final ResponseEntity response = controllerUnderTest.submitApplication(submitApplication);
+
+
+ verify(mandatoryQuestionService).getGrantMandatoryQuestionBySubmissionIdAndApplicantSub(submission.getId(), grantApplicant.getUserId());
+ verify(spotlightService, never()).createSpotlightCheck(Mockito.any(), Mockito.any());
+ verify(submissionService).getSubmissionFromDatabaseBySubmissionId(APPLICANT_USER_ID, SUBMISSION_ID);
+ verify(submissionService).submit(submission, grantApplicant, emailAddress);
+
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(response.getBody()).isEqualTo("Submitted");
+ }
+
@Test
void submitApplication_ThrowsNotFoundException_IfSubmissionNotFound() {
From f0a195986d1e50c301dac4da5d9b4ce64776fc04 Mon Sep 17 00:00:00 2001
From: Conor Fayle <141320269+ConorFayleTCO@users.noreply.github.com>
Date: Mon, 20 Nov 2023 15:59:56 +0000
Subject: [PATCH 04/19] GAP-2249: Conditional Logic - Changes to submission for
applicant types (#58)
* GAP-2249 | reorder submission questions, conditionally remove questions if individual or non-limited company, conditionally change title if individual
* GAP-2249 | use org types from constants
---------
Co-authored-by: conor
---
.../constants/MandatoryQuestionConstants.java | 31 ++--
.../enums/GrantApplicantOrganisationType.java | 2 +-
.../enums/GrantMandatoryQuestionOrgType.java | 2 +-
.../GrantMandatoryQuestionService.java | 59 +++++---
.../GrantMandatoryQuestionServiceTest.java | 133 +++++++++++++++++-
5 files changed, 195 insertions(+), 32 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/constants/MandatoryQuestionConstants.java b/src/main/java/gov/cabinetoffice/gap/applybackend/constants/MandatoryQuestionConstants.java
index 8f2bbdc8..f47d31e6 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/constants/MandatoryQuestionConstants.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/constants/MandatoryQuestionConstants.java
@@ -1,14 +1,18 @@
package gov.cabinetoffice.gap.applybackend.constants;
+import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionOrgType;
+
public class MandatoryQuestionConstants {
public static final String ORGANISATION_DETAILS_SECTION_ID = "ORGANISATION_DETAILS";
- public static final String ORGANISATION_DETAILS_SECTION_TITLE = "Your Organisation";
+ public static final String ORGANISATION_DETAILS_SECTION_TITLE = "Your organisation";
+ public static final String ORGANISATION_INDIVIDUAL_DETAILS_SECTION_TITLE = "Your details";
public static final String FUNDING_DETAILS_SECTION_ID = "FUNDING_DETAILS";
public static final String FUNDING_DETAILS_SECTION_TITLE = "Funding";
public static final String APPLICANT_ORG_NAME_TITLE = "Enter the name of your organisation";
+ public static final String APPLICANT_SUBMISSION_ORG_NAME_TITLE = "Name";
public static final String APPLICANT_ORG_NAME_PROFILE_FIELD = "ORG_NAME";
public static final String APPLICANT_ORG_NAME_HINT = "This is the official name of your organisation. It could be the name that is registered with Companies House or the Charities Commission";
public static final String APPLICANT_ORG_NAME_ADMIN_SUMMARY = "organisation legal name";
@@ -16,35 +20,38 @@ public class MandatoryQuestionConstants {
public static final int APPLICANT_ORG_NAME_MAX_LENGTH = 250;
public static final String APPLICANT_TYPE_TITLE = "Choose your organisation type";
+ public static final String APPLICANT_SUBMISSION_TYPE_TITLE = "Type of organisation";
+ public static final String APPLICANT_INDIVIDUAL_SUBMISSION_TYPE_TITLE = "Type of application";
public static final String APPLICANT_TYPE_PROFILE_FIELD = "ORG_TYPE";
public static final String APPLICANT_TYPE_HINT_TEXT = "Choose the option that best describes your organisation";
public static final String APPLICANT_TYPE_ADMIN_SUMMARY = "organisation type (e.g. limited company)";
public static final String[] APPLICANT_TYPE_OPTIONS = new String[] {
- "Limited company",
- "Non-limited company",
- "Registered charity",
- "Unregistered charity",
- "Other",
- "Charity",
- "I am applying as an Individual",
+ GrantMandatoryQuestionOrgType.LIMITED_COMPANY.toString(),
+ GrantMandatoryQuestionOrgType.NON_LIMITED_COMPANY.toString(),
+ GrantMandatoryQuestionOrgType.REGISTERED_CHARITY.toString(),
+ GrantMandatoryQuestionOrgType.UNREGISTERED_CHARITY.toString(),
+ GrantMandatoryQuestionOrgType.OTHER.toString(),
+ GrantMandatoryQuestionOrgType.CHARITY.toString(),
+ GrantMandatoryQuestionOrgType.INDIVIDUAL.toString(),
};
public static final String ORGANISATION_ADDRESS_TITLE = "Enter your organisations address";
+ public static final String ORGANISATION_SUBMISSION_ADDRESS_TITLE = "Address";
public static final String ORGANISATION_ADDRESS_PROFILE_FIELD = "ORG_ADDRESS";
public static final String ORGANISATION_ADDRESS_ADMIN_SUMMARY = "Enter your organisations address";
- public static final String CHARITY_COMMISSION_NUMBER_TITLE = "Enter your Charity Commission number (if you have one)";
+ public static final String CHARITY_COMMISSION_NUMBER_TITLE = "Enter your Charity Commission number";
public static final String CHARITY_COMMISSION_NUMBER_PROFILE_FIELD = "ORG_CHARITY_NUMBER";
public static final String CHARITY_COMMISSION_NUMBER_HINT_TEXT = "Funding organisation might use this to identify your organisation when you apply for a grant. It might also be used to check your organisation is legitimate.";
- public static final String CHARITY_COMMISSION_NUMBER_ADMIN_SUMMARY = "Charity Commission number (if applicable)";
+ public static final String CHARITY_COMMISSION_NUMBER_ADMIN_SUMMARY = "Charity Commission number";
public static final int CHARITY_COMMISSION_NUMBER_MIN_LENGTH = 2;
public static final int CHARITY_COMMISSION_NUMBER_MAX_LENGTH = 15;
public static final String CHARITY_COMMISSION_NUMBER_VALID_INPUT = "alphanumeric-nospace";
- public static final String COMPANIES_HOUSE_NUMBER_TITLE = "Enter your Companies House number (if you have one)";
+ public static final String COMPANIES_HOUSE_NUMBER_TITLE = "Enter your Companies House number";
public static final String COMPANIES_HOUSE_NUMBER_PROFILE_FIELD = "ORG_COMPANIES_HOUSE";
public static final String COMPANIES_HOUSE_NUMBER_HINT_TEXT = "Funding organisation might use this to identify your organisation when you apply for a grant. It might also be used to check your organisation is legitimate.";
- public static final String COMPANIES_HOUSE_NUMBER_ADMIN_SUMMARY = "Companies House number (if applicable)";
+ public static final String COMPANIES_HOUSE_NUMBER_ADMIN_SUMMARY = "Companies House number";
public static final int COMPANIES_HOUSE_NUMBER_MIN_LENGTH = 2;
public static final int COMPANIES_HOUSE_NUMBER_MAX_LENGTH = 8;
public static final String COMPANIES_HOUSE_NUMBER_VALID_INPUT = "alphanumeric-nospace";
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantApplicantOrganisationType.java b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantApplicantOrganisationType.java
index c0789e2a..1b5d26eb 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantApplicantOrganisationType.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantApplicantOrganisationType.java
@@ -9,7 +9,7 @@ public enum GrantApplicantOrganisationType {
REGISTERED_CHARITY("Registered charity"),
UNREGISTERED_CHARITY("Unregistered charity"),
CHARITY("Charity"),
- INDIVIDUAL("I am applying as an Individual"),
+ INDIVIDUAL("I am applying as an individual"),
OTHER("Other");
private String name;
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionOrgType.java b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionOrgType.java
index ee7a4c8e..173c9101 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionOrgType.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionOrgType.java
@@ -8,7 +8,7 @@ public enum GrantMandatoryQuestionOrgType {
REGISTERED_CHARITY("Registered charity"),
UNREGISTERED_CHARITY("Unregistered charity"),
CHARITY("Charity"),
- INDIVIDUAL("I am applying as an Individual"),
+ INDIVIDUAL("I am applying as an individual"),
OTHER("Other");
private String name;
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
index 1b98e914..a7510f4c 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
@@ -161,22 +161,45 @@ public void addMandatoryQuestionsToSubmissionObject(final GrantMandatoryQuestion
}
public SubmissionSection buildOrganisationDetailsSubmissionSection(final GrantMandatoryQuestions mandatoryQuestions, final SubmissionSectionStatus sectionStatus) {
- final SubmissionQuestion organisationName = mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_NAME.toString(), mandatoryQuestions);
- final SubmissionQuestion applicantType = mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_TYPE.toString(), mandatoryQuestions);
- final SubmissionQuestion organisationAddress = mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_ADDRESS.toString(), mandatoryQuestions);
- final SubmissionQuestion charityCommissionNumber = mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_CHARITY_NUMBER.toString(), mandatoryQuestions);
- final SubmissionQuestion companiesHouseNumber = mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_COMPANIES_HOUSE.toString(), mandatoryQuestions);
+ final boolean isNonLimitedCompany = Objects.equals(mandatoryQuestions.getOrgType().toString(), GrantMandatoryQuestionOrgType.NON_LIMITED_COMPANY.toString());
+ final boolean isIndividual = Objects.equals(mandatoryQuestions.getOrgType().toString(), GrantMandatoryQuestionOrgType.INDIVIDUAL.toString());
+ final String sectionTitle = isIndividual
+ ? MandatoryQuestionConstants.ORGANISATION_INDIVIDUAL_DETAILS_SECTION_TITLE
+ : MandatoryQuestionConstants.ORGANISATION_DETAILS_SECTION_TITLE;
+ final SubmissionQuestion organisationName = mandatoryQuestionToSubmissionQuestion(
+ MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_NAME.toString(),
+ mandatoryQuestions
+ );
+ final SubmissionQuestion applicantType = mandatoryQuestionToSubmissionQuestion(
+ MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_TYPE.toString(),
+ mandatoryQuestions
+ );
+ final SubmissionQuestion organisationAddress = mandatoryQuestionToSubmissionQuestion(
+ MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_ADDRESS.toString(),
+ mandatoryQuestions
+ );
+
+ List questions = new ArrayList<>();
+ questions.add(applicantType);
+ questions.add(organisationName);
+ questions.add(organisationAddress);
+ if (!isIndividual && !isNonLimitedCompany) {
+ final SubmissionQuestion charityCommissionNumber = mandatoryQuestionToSubmissionQuestion(
+ MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_CHARITY_NUMBER.toString(),
+ mandatoryQuestions
+ );
+ final SubmissionQuestion companiesHouseNumber = mandatoryQuestionToSubmissionQuestion(
+ MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_COMPANIES_HOUSE.toString(),
+ mandatoryQuestions
+ );
+ questions.add(charityCommissionNumber);
+ questions.add(companiesHouseNumber);
+ }
return SubmissionSection.builder()
.sectionId(MandatoryQuestionConstants.ORGANISATION_DETAILS_SECTION_ID)
- .sectionTitle(MandatoryQuestionConstants.ORGANISATION_DETAILS_SECTION_TITLE)
- .questions(List.of(
- organisationName,
- applicantType,
- organisationAddress,
- charityCommissionNumber,
- companiesHouseNumber
- ))
+ .sectionTitle(sectionTitle)
+ .questions(questions)
.sectionStatus(sectionStatus)
.build();
}
@@ -230,7 +253,7 @@ private SubmissionQuestion buildOrganisationNameQuestion(final GrantMandatoryQue
return SubmissionQuestion.builder()
.questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_NAME.toString())
- .fieldTitle(MandatoryQuestionConstants.APPLICANT_ORG_NAME_TITLE)
+ .fieldTitle(MandatoryQuestionConstants.APPLICANT_SUBMISSION_ORG_NAME_TITLE)
.profileField(MandatoryQuestionConstants.APPLICANT_ORG_NAME_PROFILE_FIELD)
.hintText(MandatoryQuestionConstants.APPLICANT_ORG_NAME_HINT)
.adminSummary(MandatoryQuestionConstants.APPLICANT_ORG_NAME_ADMIN_SUMMARY)
@@ -245,9 +268,13 @@ private SubmissionQuestion buildApplicationTypeQuestion(final GrantMandatoryQues
.mandatory(true)
.build();
+ final String title = Objects.equals(mandatoryQuestions.getOrgType().toString(), GrantMandatoryQuestionOrgType.INDIVIDUAL.toString())
+ ? MandatoryQuestionConstants.APPLICANT_INDIVIDUAL_SUBMISSION_TYPE_TITLE
+ : MandatoryQuestionConstants.APPLICANT_SUBMISSION_TYPE_TITLE;
+
return SubmissionQuestion.builder()
.questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_TYPE.toString())
- .fieldTitle(MandatoryQuestionConstants.APPLICANT_TYPE_TITLE)
+ .fieldTitle(title)
.profileField(MandatoryQuestionConstants.APPLICANT_TYPE_PROFILE_FIELD)
.hintText(MandatoryQuestionConstants.APPLICANT_ORG_NAME_HINT)
.adminSummary(MandatoryQuestionConstants.APPLICANT_TYPE_ADMIN_SUMMARY)
@@ -353,7 +380,7 @@ private SubmissionQuestion buildOrganisationAddressQuestion(final GrantMandatory
return SubmissionQuestion.builder()
.questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_ADDRESS.toString())
- .fieldTitle(MandatoryQuestionConstants.ORGANISATION_ADDRESS_TITLE)
+ .fieldTitle(MandatoryQuestionConstants.ORGANISATION_SUBMISSION_ADDRESS_TITLE)
.profileField(MandatoryQuestionConstants.ORGANISATION_ADDRESS_PROFILE_FIELD)
.adminSummary(MandatoryQuestionConstants.ORGANISATION_ADDRESS_ADMIN_SUMMARY)
.responseType(SubmissionQuestionResponseType.AddressInput)
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
index 73362024..c2e44e06 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
@@ -652,7 +652,7 @@ void addMandatoryQuestions() {
class buildOrganisationDetailsSubmissionSection {
@Test
- void addsCorrectDetails() {
+ void addsCorrectDetailsForLimitedCompany() {
final SubmissionSectionStatus status = SubmissionSectionStatus.IN_PROGRESS;
@@ -677,6 +677,7 @@ void addsCorrectDetails() {
.build();
final GrantMandatoryQuestions mandatoryQuestions = GrantMandatoryQuestions.builder()
+ .orgType(GrantMandatoryQuestionOrgType.LIMITED_COMPANY)
.submission(submission)
.build();
@@ -723,13 +724,141 @@ void addsCorrectDetails() {
assertThat(orgDetailsSection.getSectionTitle()).isEqualTo(MandatoryQuestionConstants.ORGANISATION_DETAILS_SECTION_TITLE);
assertThat(orgDetailsSection.getSectionStatus()).isEqualTo(status);
assertThat(orgDetailsSection.getQuestions()).containsExactlyElementsOf(List.of(
- orgName,
applicantType,
+ orgName,
orgAddress,
charityNumber,
companiesHouse
));
}
+
+ @Test
+ void addsCorrectDetailsForNonLimitedCompany() {
+
+ final SubmissionSectionStatus status = SubmissionSectionStatus.IN_PROGRESS;
+
+ final SubmissionSection eligibility = SubmissionSection.builder()
+ .sectionId("ELIGIBILITY")
+ .build();
+
+ final SubmissionSection organisationDetails = SubmissionSection.builder()
+ .sectionId("ORGANISATION_DETAILS")
+ .build();
+
+ final SubmissionSection fundingDetails = SubmissionSection.builder()
+ .sectionId("FUNDING_DETAILS")
+ .build();
+
+ final SubmissionDefinition definition = SubmissionDefinition.builder()
+ .sections(new ArrayList(List.of(eligibility, organisationDetails, fundingDetails)))
+ .build();
+
+ final Submission submission = Submission.builder()
+ .definition(definition)
+ .build();
+
+ final GrantMandatoryQuestions mandatoryQuestions = GrantMandatoryQuestions.builder()
+ .orgType(GrantMandatoryQuestionOrgType.NON_LIMITED_COMPANY)
+ .submission(submission)
+ .build();
+
+ final SubmissionQuestion orgName = SubmissionQuestion.builder()
+ .questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_NAME.toString())
+ .build();
+
+ final SubmissionQuestion applicantType = SubmissionQuestion.builder()
+ .questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_TYPE.toString())
+ .build();
+
+ final SubmissionQuestion orgAddress = SubmissionQuestion.builder()
+ .questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_ADDRESS.toString())
+ .build();
+
+ doReturn(orgName)
+ .when(serviceUnderTest).mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_NAME.toString(), mandatoryQuestions);
+
+ doReturn(applicantType)
+ .when(serviceUnderTest).mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_TYPE.toString(), mandatoryQuestions);
+
+ doReturn(orgAddress)
+ .when(serviceUnderTest).mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_ADDRESS.toString(), mandatoryQuestions);
+
+ final SubmissionSection orgDetailsSection = serviceUnderTest.buildOrganisationDetailsSubmissionSection(mandatoryQuestions, status);
+
+
+ assertThat(orgDetailsSection.getSectionId()).isEqualTo(MandatoryQuestionConstants.ORGANISATION_DETAILS_SECTION_ID);
+ assertThat(orgDetailsSection.getSectionTitle()).isEqualTo(MandatoryQuestionConstants.ORGANISATION_DETAILS_SECTION_TITLE);
+ assertThat(orgDetailsSection.getSectionStatus()).isEqualTo(status);
+ assertThat(orgDetailsSection.getQuestions()).containsExactlyElementsOf(List.of(
+ applicantType,
+ orgName,
+ orgAddress
+ ));
+ }
+
+ @Test
+ void addsCorrectDetailsForIndividual() {
+
+ final SubmissionSectionStatus status = SubmissionSectionStatus.IN_PROGRESS;
+
+ final SubmissionSection eligibility = SubmissionSection.builder()
+ .sectionId("ELIGIBILITY")
+ .build();
+
+ final SubmissionSection organisationDetails = SubmissionSection.builder()
+ .sectionId("ORGANISATION_DETAILS")
+ .build();
+
+ final SubmissionSection fundingDetails = SubmissionSection.builder()
+ .sectionId("FUNDING_DETAILS")
+ .build();
+
+ final SubmissionDefinition definition = SubmissionDefinition.builder()
+ .sections(new ArrayList(List.of(eligibility, organisationDetails, fundingDetails)))
+ .build();
+
+ final Submission submission = Submission.builder()
+ .definition(definition)
+ .build();
+
+ final GrantMandatoryQuestions mandatoryQuestions = GrantMandatoryQuestions.builder()
+ .orgType(GrantMandatoryQuestionOrgType.INDIVIDUAL)
+ .submission(submission)
+ .build();
+
+ final SubmissionQuestion orgName = SubmissionQuestion.builder()
+ .questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_NAME.toString())
+ .build();
+
+ final SubmissionQuestion applicantType = SubmissionQuestion.builder()
+ .questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_TYPE.toString())
+ .build();
+
+ final SubmissionQuestion orgAddress = SubmissionQuestion.builder()
+ .questionId(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_ADDRESS.toString())
+ .build();
+
+ doReturn(orgName)
+ .when(serviceUnderTest).mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_NAME.toString(), mandatoryQuestions);
+
+ doReturn(applicantType)
+ .when(serviceUnderTest).mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_TYPE.toString(), mandatoryQuestions);
+
+ doReturn(orgAddress)
+ .when(serviceUnderTest).mandatoryQuestionToSubmissionQuestion(MandatoryQuestionConstants.SUBMISSION_QUESTION_IDS.APPLICANT_ORG_ADDRESS.toString(), mandatoryQuestions);
+
+ final SubmissionSection orgDetailsSection = serviceUnderTest.buildOrganisationDetailsSubmissionSection(mandatoryQuestions, status);
+
+
+ assertThat(orgDetailsSection.getSectionId()).isEqualTo(MandatoryQuestionConstants.ORGANISATION_DETAILS_SECTION_ID);
+ assertThat(orgDetailsSection.getSectionTitle()).isEqualTo(MandatoryQuestionConstants.ORGANISATION_INDIVIDUAL_DETAILS_SECTION_TITLE);
+ assertThat(orgDetailsSection.getSectionStatus()).isEqualTo(status);
+ assertThat(orgDetailsSection.getQuestions()).containsExactlyElementsOf(List.of(
+ applicantType,
+ orgName,
+ orgAddress
+ ));
+ }
}
@Nested
From 3e95d745f33ed2b1d2c4a3a945e4147494000a5d Mon Sep 17 00:00:00 2001
From: Conor Fayle <141320269+ConorFayleTCO@users.noreply.github.com>
Date: Tue, 21 Nov 2023 11:51:49 +0000
Subject: [PATCH 05/19] GAP-2249: fix save submission (#59)
* GAP-2249 | fix submitting application
* GAP-2249 | remove comment on line
---------
Co-authored-by: conor
---
.../service/SubmissionService.java | 24 ++++++++-----------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java
index 5fe13988..a4a1ab31 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java
@@ -272,36 +272,32 @@ private void submitApplication(final Submission submission) {
}
private void createDiligenceCheckFromSubmission(final Submission submission) {
- final String organisationName = getQuestionResponseByQuestionId(submission, APPLICANT_ORG_NAME);
+ final Optional organisationName = getQuestionResponseByQuestionId(submission, APPLICANT_ORG_NAME);
final String[] organisationAddress = getQuestionMultiResponseByQuestionId(submission, APPLICANT_ORG_ADDRESS);
- final String applicationAmount = getQuestionResponseByQuestionId(submission, APPLICANT_AMOUNT);
- final String companiesHouseNumber = getQuestionResponseByQuestionId(submission, APPLICANT_ORG_COMPANIES_HOUSE);
- final String charitiesCommissionNumber = getQuestionResponseByQuestionId(submission, APPLICANT_ORG_CHARITY_NUMBER);
+ final Optional applicationAmount = getQuestionResponseByQuestionId(submission, APPLICANT_AMOUNT);
+ final Optional companiesHouseNumber = getQuestionResponseByQuestionId(submission, APPLICANT_ORG_COMPANIES_HOUSE);
+ final Optional charitiesCommissionNumber = getQuestionResponseByQuestionId(submission, APPLICANT_ORG_CHARITY_NUMBER);
diligenceCheckRepository.save(DiligenceCheck.builder()
.submissionId(submission.getId())
.applicationNumber(submission.getGapId())
- .organisationName(organisationName)
+ .organisationName(organisationName.map(SubmissionQuestion::getResponse).orElse(null))
.addressStreet(organisationAddress[0])
.addressTown(organisationAddress[2])
.addressCounty(organisationAddress[3])
.addressPostcode(organisationAddress[4])
- .applicationAmount(applicationAmount)
- .companiesHouseNumber(companiesHouseNumber)
- .charityNumber(charitiesCommissionNumber)
+ .applicationAmount(applicationAmount.map(SubmissionQuestion::getResponse).orElse(null))
+ .companiesHouseNumber(companiesHouseNumber.map(SubmissionQuestion::getResponse).orElse(null))
+ .charityNumber(charitiesCommissionNumber.map(SubmissionQuestion::getResponse).orElse(null))
.build());
}
- private String getQuestionResponseByQuestionId(final Submission submission, final String questionId) {
+ private Optional getQuestionResponseByQuestionId(final Submission submission, final String questionId) {
return submission.getDefinition().getSections()
.stream()
.flatMap(s -> s.getQuestions().stream())
.filter(question -> question.getQuestionId().equals(questionId))
- .findAny()
- .orElseThrow(() -> new IllegalArgumentException(
- String.format("submission %s does not contain a question with an ID of %s",
- submission.getId(), questionId)))
- .getResponse();
+ .findAny();
}
private String[] getQuestionMultiResponseByQuestionId(final Submission submission, final String questionId) {
From 1f802c8e1b2a2d96c9c954585ba8b2afa1f338a4 Mon Sep 17 00:00:00 2001
From: ryan-tco <135323857+ryan-tco@users.noreply.github.com>
Date: Wed, 22 Nov 2023 14:50:38 +0000
Subject: [PATCH 06/19] GAP-2257 Disallow Special Chars in Answer Boxes (#60)
---
.../validators/QuestionResponseValidator.java | 9 +++++++++
.../annotations/QuestionResponseValidatorTest.java | 11 +++++++++++
2 files changed, 20 insertions(+)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
index 9cff4df6..65f12434 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
@@ -139,6 +139,11 @@ private ValidationResult validate(CreateQuestionResponseDto submittedQuestion, S
}
}
+ if(containsSpecialCharacters(submittedQuestion.getResponse())) {
+ result.addError(ValidationConstants.SINGLE_RESPONSE_FIELD, "Answer must only include letters, numbers, and special characters such as hyphens, spaces and apostrophes");
+ return result;
+ }
+
result.setValid(Boolean.TRUE);
return result;
}
@@ -210,6 +215,10 @@ private int getNumberOfWords(String response) {
return Strings.isEmpty(response) ? 0 : response.split("\\s").length;
}
+ private boolean containsSpecialCharacters(String response) {
+ return !response.matches("^(?![\\s\\S])|^[a-zA-Z0-9à-üÀ-Ü\\s',!@£$%^&*()_+=\\[\\];./?><:\"{}|`~-]+$");
+ }
+
private ValidationResult validateDate(final String[] dateComponents, final boolean isMandatory) {
ValidationResult dateValidationResult = ValidationResult.builder().build();
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/validation/annotations/QuestionResponseValidatorTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/validation/annotations/QuestionResponseValidatorTest.java
index d95e5539..b3d9b62c 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/validation/annotations/QuestionResponseValidatorTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/validation/annotations/QuestionResponseValidatorTest.java
@@ -155,6 +155,17 @@ private static Stream provideTestData() {
, "Answer must only include numeric values/ decimal",
SubmissionQuestionValidation.builder()
.greaterThanZero(true)
+ .build()),
+
+ // Special characters check should fail
+ Arguments.of(
+ CreateQuestionResponseDto.builder()
+ .questionId(questionId)
+ .submissionId(submissionId)
+ .response("\uDBFF\uDC05")
+ .build()
+ , "Answer must only include letters, numbers, and special characters such as hyphens, spaces and apostrophes",
+ SubmissionQuestionValidation.builder()
.build())
);
From d4888c83ab70c3e23574eb104d38d662169da490 Mon Sep 17 00:00:00 2001
From: dominicwest <101722961+dominicwest@users.noreply.github.com>
Date: Thu, 23 Nov 2023 15:49:07 +0000
Subject: [PATCH 07/19] GAP-2303: Eagerly fetching scheme ads & application
(#61)
GAP-2303: Eagerly fetching scheme ads & application (#61)
---
pull_request_template.md | 36 +++++++++++++++
.../dto/api/GetGrantApplicationDto.java | 20 ++++++++
.../dto/api/GetGrantSchemeDto.java | 43 +++++++++--------
...tGrantSchemeWithApplicationAndAdverts.java | 14 ++++++
.../mapper/GrantSchemeMapper.java | 18 ++++++++
.../gap/applybackend/model/GrantScheme.java | 28 +++++------
.../repository/GrantSchemeRepository.java | 8 ++++
.../service/GrantAdvertService.java | 25 +++++++++-
.../service/GrantSchemeService.java | 2 +-
.../web/GrantSchemeController.java | 31 +++++++++++--
.../service/GrantSchemeServiceTest.java | 8 ++--
.../web/GrantSchemeControllerTest.java | 46 +++++++++++++++++--
12 files changed, 231 insertions(+), 48 deletions(-)
create mode 100644 pull_request_template.md
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantApplicationDto.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeWithApplicationAndAdverts.java
create mode 100644 src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantSchemeMapper.java
diff --git a/pull_request_template.md b/pull_request_template.md
new file mode 100644
index 00000000..bfe3eb4f
--- /dev/null
+++ b/pull_request_template.md
@@ -0,0 +1,36 @@
+## Description
+
+Ticket # and link
+
+Summary of the changes and the related issue. List any dependencies that are required for this change:
+
+## Type of change
+
+Please check the relevant options.
+
+- [ ] Bug fix (non-breaking change which fixes an issue).
+- [ ] New feature (non-breaking change which adds functionality).
+- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected).
+- [ ] This change requires a documentation update.
+
+## How Has This Been Tested?
+
+Please describe the tests that you ran to verify your changes:
+
+- [ ] Unit Test
+
+- [ ] Integration Test (if applicable)
+
+- [ ] End to End Test (if applicable)
+
+## Screenshots (if appropriate):
+
+Please attach screenshots of the change if it is a UI change:
+
+# Checklist:
+
+- [ ] If I have listed dependencies above, I have ensured that they are present in the target branch.
+- [ ] I have performed a self-review of my code.
+- [ ] I have commented my code in hard-to-understand areas.
+- [ ] I have made corresponding changes to the documentation where applicable.
+- [ ] I have ran cypress tests and they all pass locally.
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantApplicationDto.java b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantApplicationDto.java
new file mode 100644
index 00000000..8d513c6a
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantApplicationDto.java
@@ -0,0 +1,20 @@
+package gov.cabinetoffice.gap.applybackend.dto.api;
+
+import gov.cabinetoffice.gap.applybackend.enums.GrantApplicantStatus;
+import lombok.Data;
+import lombok.RequiredArgsConstructor;
+
+import java.time.Instant;
+
+@Data
+@RequiredArgsConstructor
+public class GetGrantApplicationDto {
+ private Integer id;
+ private Integer grantSchemeId;
+ private Integer version;
+ private Instant created;
+ private Instant lastUpdated;
+ private Integer lastUpdatedBy;
+ private String applicationName;
+ private GrantApplicantStatus applicationStatus;
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeDto.java b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeDto.java
index 90ba3376..75a462c6 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeDto.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeDto.java
@@ -1,26 +1,33 @@
package gov.cabinetoffice.gap.applybackend.dto.api;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
+import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.RequiredArgsConstructor;
-import java.time.ZonedDateTime;
+import java.time.Instant;
-@NoArgsConstructor
-@AllArgsConstructor
-@Builder
@Data
+@RequiredArgsConstructor
public class GetGrantSchemeDto {
- private long id;
- private long funderId;
- private int version;
- private ZonedDateTime lastUpdated;
- private long lastUpdatedBy;
+ private Integer id;
+ private Integer funderId;
+ private Integer version;
+ private Instant createdDate;
+ private Instant lastUpdated;
+ private Integer lastUpdatedBy;
private String ggisIdentifier;
- private String schemeName;
- private String schemeContact;
- private String sectionId;
- private String sectionTitle;
- private String sectionStatus;
-}
+ private String name;
+ private String email;
+
+ public GetGrantSchemeDto(final GrantScheme grantScheme) {
+ this.id = grantScheme.getId();
+ this.funderId = grantScheme.getFunderId();
+ this.version = grantScheme.getVersion();
+ this.createdDate = grantScheme.getCreatedDate();
+ this.lastUpdated = grantScheme.getLastUpdated();
+ this.lastUpdatedBy = grantScheme.getLastUpdatedBy();
+ this.ggisIdentifier = grantScheme.getGgisIdentifier();
+ this.name = grantScheme.getName();
+ this.email = grantScheme.getEmail();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeWithApplicationAndAdverts.java b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeWithApplicationAndAdverts.java
new file mode 100644
index 00000000..5b73cb85
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantSchemeWithApplicationAndAdverts.java
@@ -0,0 +1,14 @@
+package gov.cabinetoffice.gap.applybackend.dto.api;
+
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Builder
+public class GetGrantSchemeWithApplicationAndAdverts {
+ private GetGrantSchemeDto grantScheme;
+ private GetGrantApplicationDto grantApplication;
+ private List grantAdverts;
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantSchemeMapper.java b/src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantSchemeMapper.java
new file mode 100644
index 00000000..90040fb1
--- /dev/null
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantSchemeMapper.java
@@ -0,0 +1,18 @@
+package gov.cabinetoffice.gap.applybackend.mapper;
+
+import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantApplicationDto;
+import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantSchemeDto;
+import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.NullValueCheckStrategy;
+import org.mapstruct.NullValuePropertyMappingStrategy;
+
+
+@Mapper(componentModel = "spring", nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
+public interface GrantSchemeMapper {
+ GetGrantSchemeDto grantSchemeToGetGrantSchemeDto(GrantScheme grantScheme);
+
+ @Mapping(source = "grantApplication", target = ".")
+ GetGrantApplicationDto grantSchemeToGetGrantApplicationDto(GrantScheme grantScheme);
+}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
index 798b51fa..ef154b30 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
@@ -1,19 +1,11 @@
package gov.cabinetoffice.gap.applybackend.model;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.ToString;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.Table;
+import lombok.*;
+
+import javax.persistence.*;
import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
@Entity
@Table(name = "grant_scheme")
@@ -26,7 +18,7 @@
public class GrantScheme {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "grant_scheme_id")
+ @Column(name = "grant_scheme_id", nullable = false)
private Integer id;
@Column(name = "funder_id", nullable = false)
@@ -54,4 +46,12 @@ public class GrantScheme {
@Column(name = "scheme_contact")
private String email;
+
+ @ToString.Exclude
+ @OneToMany(mappedBy = "scheme", orphanRemoval = true, cascade = CascadeType.ALL)
+ private List grantAdverts = new ArrayList<>();
+
+ @ToString.Exclude
+ @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "grantScheme")
+ private GrantApplication grantApplication;
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantSchemeRepository.java b/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantSchemeRepository.java
index 6bbb2738..c55ab363 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantSchemeRepository.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantSchemeRepository.java
@@ -1,7 +1,15 @@
package gov.cabinetoffice.gap.applybackend.repository;
+import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantSchemeDto;
import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
+import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+
+import java.util.Optional;
public interface GrantSchemeRepository extends JpaRepository {
+ @Query("select g from GrantScheme g where g.id = ?1")
+ @EntityGraph(attributePaths = {"grantApplication", "grantAdverts"})
+ Optional findByIdWithApplicationAndAdverts(Integer integer);
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java
index 18dff640..3aa4d868 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java
@@ -8,11 +8,15 @@
import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantAdvertDto;
import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantMandatoryQuestionDto;
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
+import gov.cabinetoffice.gap.applybackend.mapper.GrantMandatoryQuestionMapper;
import gov.cabinetoffice.gap.applybackend.model.GrantAdvert;
import gov.cabinetoffice.gap.applybackend.model.GrantAdvertQuestionResponse;
+import gov.cabinetoffice.gap.applybackend.model.GrantApplicant;
+import gov.cabinetoffice.gap.applybackend.model.GrantMandatoryQuestions;
import gov.cabinetoffice.gap.applybackend.repository.GrantAdvertRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@Service
@@ -21,9 +25,11 @@
public class GrantAdvertService {
private final GrantAdvertRepository grantAdvertRepository;
-
+ private final GrantMandatoryQuestionMapper grantMandatoryQuestionMapper;
private final GrantApplicationService grantApplicationService;
private final CDAClient contentfulDeliveryClient;
+ private final GrantMandatoryQuestionService grantMandatoryQuestionService;
+ private final GrantApplicantService grantApplicantService;
protected static String getExternalSubmissionUrl(GrantAdvert advert) {
return advert.getResponse().getSections().stream()
@@ -84,4 +90,21 @@ public GrantAdvert getAdvertBySchemeId(String schemeId) {
log.debug("Advert with schemeId {} found", schemeId);
return grantAdvert;
}
+
+ public GetGrantAdvertDto grantAdvertToDto(
+ final GrantAdvert grantAdvert,
+ final String sub,
+ final Integer schemeId
+ ) {
+ final GrantApplicant grantApplicant = grantApplicantService.getApplicantById(sub);
+ GetGrantMandatoryQuestionDto mandatoryQuestionsDto = null;
+
+ if (grantMandatoryQuestionService.existsBySchemeIdAndApplicantId(schemeId, grantApplicant.getId())) {
+ final GrantMandatoryQuestions grantMandatoryQuestions = grantMandatoryQuestionService
+ .getMandatoryQuestionBySchemeId(schemeId, sub);
+ mandatoryQuestionsDto = grantMandatoryQuestionMapper.mapGrantMandatoryQuestionToGetGrantMandatoryQuestionDTO(grantMandatoryQuestions);
+ }
+
+ return generateGetGrantAdvertDto(grantAdvert, mandatoryQuestionsDto);
+ }
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java
index cc613f81..f4c67c83 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java
@@ -14,7 +14,7 @@ public class GrantSchemeService {
public GrantScheme getSchemeById(Integer schemeId) {
return grantSchemeRepository
- .findById(schemeId)
+ .findByIdWithApplicationAndAdverts(schemeId)
.orElseThrow(() -> new NotFoundException(
String.format("No Grant Scheme with ID %s was found", schemeId)));
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java
index debc0704..dabe75f0 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java
@@ -1,7 +1,10 @@
package gov.cabinetoffice.gap.applybackend.web;
-import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantSchemeDto;
+import gov.cabinetoffice.gap.applybackend.dto.api.*;
+import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
+import gov.cabinetoffice.gap.applybackend.mapper.GrantSchemeMapper;
import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
+import gov.cabinetoffice.gap.applybackend.service.GrantAdvertService;
import gov.cabinetoffice.gap.applybackend.service.GrantSchemeService;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
@@ -9,11 +12,14 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.context.SecurityContextHolder;
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.bind.annotation.RestController;
+import java.util.List;
+
@RequiredArgsConstructor
@RestController
@@ -21,14 +27,29 @@
public class GrantSchemeController {
private final GrantSchemeService grantSchemeService;
+ private final GrantSchemeMapper grantSchemeMapper;
+ private final GrantAdvertService grantAdvertService;
@GetMapping("/{grantSchemeId}")
@ApiResponses(value = {
- @ApiResponse(responseCode = "200", description = "Grant Scheme Found", content = @Content(mediaType = "application/json", schema = @Schema(implementation = GetGrantSchemeDto.class))),
+ @ApiResponse(responseCode = "200", description = "Grant Scheme Found", content = @Content(mediaType = "application/json", schema = @Schema(implementation = GetGrantSchemeWithApplicationAndAdverts.class))),
@ApiResponse(responseCode = "404", description = "No Grant Scheme found", content = @Content(mediaType = "application/json")),
})
- public ResponseEntity getGrantSchemeById(@PathVariable Integer grantSchemeId) {
- GrantScheme scheme = grantSchemeService.getSchemeById(grantSchemeId);
- return ResponseEntity.ok(scheme);
+ public ResponseEntity getGrantSchemeById(@PathVariable Integer grantSchemeId) {
+ final JwtPayload jwtPayload = (JwtPayload) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+
+ final GrantScheme grantScheme = grantSchemeService.getSchemeById(grantSchemeId);
+ final GetGrantSchemeDto grantSchemeDto = new GetGrantSchemeDto(grantScheme);
+ final GetGrantApplicationDto grantApplicationDto = grantSchemeMapper.grantSchemeToGetGrantApplicationDto(grantScheme);
+ final List grantAdvertDtos = grantScheme.getGrantAdverts().stream()
+ .map(grantAdvert -> grantAdvertService.grantAdvertToDto(grantAdvert, jwtPayload.getSub(), grantSchemeId))
+ .toList();
+
+ final GetGrantSchemeWithApplicationAndAdverts getGrantSchemeWithApplicationAndAdverts = GetGrantSchemeWithApplicationAndAdverts.builder()
+ .grantScheme(grantSchemeDto)
+ .grantApplication(grantApplicationDto)
+ .grantAdverts(grantAdvertDtos)
+ .build();
+ return ResponseEntity.ok(getGrantSchemeWithApplicationAndAdverts);
}
}
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java
index 823d2d15..030dfc18 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java
@@ -41,20 +41,20 @@ void getSchemeById_Success() {
.email("contact@contact.com")
.build();
- when(grantSchemeRepository.findById(SCHEME_ID)).thenReturn(Optional.of(scheme));
+ when(grantSchemeRepository.findByIdWithApplicationAndAdverts(SCHEME_ID)).thenReturn(Optional.of(scheme));
GrantScheme methodResponse = serviceUnderTest.getSchemeById(SCHEME_ID);
- verify(grantSchemeRepository).findById(SCHEME_ID);
+ verify(grantSchemeRepository).findByIdWithApplicationAndAdverts(SCHEME_ID);
assertEquals(methodResponse, scheme);
}
@Test
void getGrantSchemeById_OrgNotFound() {
- when(grantSchemeRepository.findById(SCHEME_ID)).thenReturn(Optional.empty());
+ when(grantSchemeRepository.findByIdWithApplicationAndAdverts(SCHEME_ID)).thenReturn(Optional.empty());
Exception result = assertThrows(NotFoundException.class, () -> serviceUnderTest.getSchemeById(SCHEME_ID));
- verify(grantSchemeRepository).findById(SCHEME_ID);
+ verify(grantSchemeRepository).findByIdWithApplicationAndAdverts(SCHEME_ID);
assertTrue(result.getMessage().contains("No Grant Scheme with ID "+ SCHEME_ID + " was found"));
}
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java
index 5afe9ec2..e9c8b7e5 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java
@@ -1,19 +1,34 @@
package gov.cabinetoffice.gap.applybackend.web;
+import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantSchemeDto;
+import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantSchemeWithApplicationAndAdverts;
+import gov.cabinetoffice.gap.applybackend.dto.api.JwtPayload;
+import gov.cabinetoffice.gap.applybackend.mapper.GrantSchemeMapper;
+import gov.cabinetoffice.gap.applybackend.model.GrantApplication;
import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
import gov.cabinetoffice.gap.applybackend.service.GrantSchemeService;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.modelmapper.ModelMapper;
+import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
import java.time.Instant;
+import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -23,9 +38,24 @@ class GrantSchemeControllerTest {
@Mock
private GrantSchemeService grantSchemeService;
@Mock
- private ModelMapper modelMapper;
+ private GrantSchemeMapper grantSchemeMapper;
@InjectMocks
private GrantSchemeController controllerUnderTest;
+ @MockBean
+ private AuthenticationManager authenticationManager;
+ @Mock
+ private Authentication authentication;
+ @Mock
+ private SecurityContext securityContext;
+ private JwtPayload jwtPayload;
+
+ @BeforeEach
+ void setup() {
+ when(securityContext.getAuthentication()).thenReturn(authentication);
+ SecurityContextHolder.setContext(securityContext);
+ jwtPayload = JwtPayload.builder().sub("sub").build();
+ when(SecurityContextHolder.getContext().getAuthentication().getPrincipal()).thenReturn(jwtPayload);
+ }
@Test
void getGrantSchemeById_ReturnsTheCorrectGrantScheme() {
@@ -38,15 +68,21 @@ void getGrantSchemeById_ReturnsTheCorrectGrantScheme() {
.ggisIdentifier("SCH-000003589")
.name("scheme_name")
.email("contact@contact.com")
+ .grantAdverts(Collections.emptyList())
+ .grantApplication(GrantApplication.builder().build())
.build();
+ final GetGrantSchemeDto getGrantSchemeDto = new GetGrantSchemeDto(grantScheme);
- when(grantSchemeService.getSchemeById(SCHEME_ID))
- .thenReturn(grantScheme);
+ when(grantSchemeService.getSchemeById(SCHEME_ID)).thenReturn(grantScheme);
- ResponseEntity response = controllerUnderTest.getGrantSchemeById(SCHEME_ID);
+ ResponseEntity response = controllerUnderTest.getGrantSchemeById(SCHEME_ID);
verify(grantSchemeService).getSchemeById(SCHEME_ID);
assertEquals(HttpStatus.OK, response.getStatusCode());
- assertEquals(response.getBody(), grantScheme);
+ assertEquals(GetGrantSchemeWithApplicationAndAdverts.builder()
+ .grantScheme(getGrantSchemeDto)
+ .grantAdverts(Collections.emptyList())
+ .grantApplication(null)
+ .build(), response.getBody());
}
}
From 9ae5fb8bc719f3ca4de4b54a1ca0fa215b9b5fb4 Mon Sep 17 00:00:00 2001
From: dominicwest <101722961+dominicwest@users.noreply.github.com>
Date: Thu, 23 Nov 2023 17:08:21 +0000
Subject: [PATCH 08/19] GAP-2251: Is org profile complete endpoint (#62)
GAP-2251: Is org profile complete endpoint (#62)
---
.../GrantApplicantOrganisationProfile.java | 14 ++
...ntApplicantOrganisationProfileService.java | 6 +
...pplicantOrganisationProfileController.java | 6 +
...plicantOrganisationProfileServiceTest.java | 182 +++++++++++++++++-
...cantOrganisationProfileControllerTest.java | 34 ++++
5 files changed, 239 insertions(+), 3 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplicantOrganisationProfile.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplicantOrganisationProfile.java
index 4f815a31..d19354e9 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplicantOrganisationProfile.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplicantOrganisationProfile.java
@@ -5,6 +5,7 @@
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
import javax.persistence.CascadeType;
import javax.persistence.Column;
@@ -60,4 +61,17 @@ public class GrantApplicantOrganisationProfile {
@Column
private String companiesHouseNumber;
+
+ public Boolean isComplete() {
+ if (StringUtils.isEmpty(legalName)) return false;
+ if (StringUtils.isEmpty(addressLine1)) return false;
+ if (StringUtils.isEmpty(town)) return false;
+ if (StringUtils.isEmpty(postcode)) return false;
+ if (type == null) return false;
+ if (type != GrantApplicantOrganisationType.INDIVIDUAL && type != GrantApplicantOrganisationType.NON_LIMITED_COMPANY) {
+ if (StringUtils.isEmpty(getCompaniesHouseNumber())) return false;
+ return !StringUtils.isEmpty(getCharityCommissionNumber());
+ }
+ return true;
+ }
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileService.java
index bc837c04..f8fd0ed7 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileService.java
@@ -37,4 +37,10 @@ public GrantApplicantOrganisationProfile createOrganisation(String applicantId,
grantApplicantService.saveApplicant(applicant);
return savedProfile;
}
+
+ public Boolean isOrganisationComplete(final String sub) {
+ final GrantApplicant applicant = grantApplicantService.getApplicantById(sub);
+ final GrantApplicantOrganisationProfile profile = applicant.getOrganisationProfile();
+ return profile.isComplete();
+ }
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileController.java b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileController.java
index 3bbf88d4..11cc9612 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileController.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileController.java
@@ -43,6 +43,12 @@ public ResponseEntity getOrganisationBy
return ResponseEntity.ok(organisationDto);
}
+ @GetMapping("/isComplete")
+ public ResponseEntity isOrganisationComplete() {
+ final JwtPayload jwtPayload = (JwtPayload) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+ return ResponseEntity.ok(grantApplicantOrganisationProfileService.isOrganisationComplete(jwtPayload.getSub()));
+ }
+
@PatchMapping("/{organisationId}")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Organisation updated", content = @Content(mediaType = "application/json", schema = @Schema(implementation = String.class))),
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileServiceTest.java
index 34d3b954..0ebf47f6 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantApplicantOrganisationProfileServiceTest.java
@@ -1,20 +1,22 @@
package gov.cabinetoffice.gap.applybackend.service;
+import gov.cabinetoffice.gap.applybackend.enums.GrantApplicantOrganisationType;
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
import gov.cabinetoffice.gap.applybackend.model.GrantApplicant;
import gov.cabinetoffice.gap.applybackend.model.GrantApplicantOrganisationProfile;
import gov.cabinetoffice.gap.applybackend.repository.GrantApplicantOrganisationProfileRepository;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -146,4 +148,178 @@ void updateOrganisation_SuccessfullyCreateOrg() {
verify(grantApplicantOrganisationProfileRepository).save(profile);
assertEquals(methodResponse, profile);
}
+
+ @Nested
+ class IsOrganisationComplete {
+ @ParameterizedTest
+ @CsvSource(value = {
+ "INDIVIDUAL,Org name,9 George Square,Glasgow,G2 1QQ,,",
+ "NON_LIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,,",
+ "LIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "UNLIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "REGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "OTHER,Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "INDIVIDUAL,Org name,9 George Square,Glasgow,G2 1QQ,null,null",
+ "NON_LIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,null,null",
+ }, nullValues = {"null"})
+ void returnsTrue(
+ final GrantApplicantOrganisationType type,
+ final String name,
+ final String addressLine1,
+ final String town,
+ final String postcode,
+ final String companiesHouseNumber,
+ final String charityCommissionNumber
+ ) {
+ final GrantApplicant applicant = GrantApplicant.builder()
+ .id(1)
+ .userId(APPLICANT_ID)
+ .build();
+ final GrantApplicantOrganisationProfile profile = GrantApplicantOrganisationProfile.builder()
+ .charityCommissionNumber(charityCommissionNumber)
+ .companiesHouseNumber(companiesHouseNumber)
+ .addressLine1(addressLine1)
+ .town(town)
+ .postcode(postcode)
+ .type(type)
+ .legalName(name)
+ .build();
+ applicant.setOrganisationProfile(profile);
+
+ when(grantApplicantService.getApplicantById(APPLICANT_ID)).thenReturn(applicant);
+
+ Boolean methodResponse = serviceUnderTest.isOrganisationComplete(APPLICANT_ID);
+
+ verify(grantApplicantService).getApplicantById(APPLICANT_ID);
+ assertTrue(methodResponse);
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {
+ ",Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "INDIVIDUAL,Org name,9 George Square,Glasgow,,45,000010",
+ "INDIVIDUAL,Org name,9 George Square,,G2 1QQ,45,000010",
+ "INDIVIDUAL,Org name,,Glasgow,G2 1QQ,45,000010",
+ "INDIVIDUAL,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "NON_LIMITED_COMPANY,Org name,9 George Square,Glasgow,,45,000010",
+ "NON_LIMITED_COMPANY,Org name,9 George Square,,G2 1QQ,45,000010",
+ "NON_LIMITED_COMPANY,Org name,,Glasgow,G2 1QQ,45,000010",
+ "NON_LIMITED_COMPANY,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "LIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,45,",
+ "LIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,,000010",
+ "LIMITED_COMPANY,Org name,9 George Square,Glasgow,,45,000010",
+ "LIMITED_COMPANY,Org name,9 George Square,,G2 1QQ,45,000010",
+ "LIMITED_COMPANY,Org name,,Glasgow,G2 1QQ,45,000010",
+ "LIMITED_COMPANY,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "UNLIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,45,",
+ "UNLIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,,000010",
+ "UNLIMITED_COMPANY,Org name,9 George Square,Glasgow,,45,000010",
+ "UNLIMITED_COMPANY,Org name,9 George Square,,G2 1QQ,45,000010",
+ "UNLIMITED_COMPANY,Org name,,Glasgow,G2 1QQ,45,000010",
+ "UNLIMITED_COMPANY,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "REGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,",
+ "REGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,,000010",
+ "REGISTERED_CHARITY,Org name,9 George Square,Glasgow,,45,000010",
+ "REGISTERED_CHARITY,Org name,9 George Square,,G2 1QQ,45,000010",
+ "REGISTERED_CHARITY,Org name,,Glasgow,G2 1QQ,45,000010",
+ "REGISTERED_CHARITY,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,,000010",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,Glasgow,,45,000010",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,,G2 1QQ,45,000010",
+ "UNREGISTERED_CHARITY,Org name,,Glasgow,G2 1QQ,45,000010",
+ "UNREGISTERED_CHARITY,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,",
+ "CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,,000010",
+ "CHARITY,Org name,9 George Square,Glasgow,,45,000010",
+ "CHARITY,Org name,9 George Square,,G2 1QQ,45,000010",
+ "CHARITY,Org name,,Glasgow,G2 1QQ,45,000010",
+ "CHARITY,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "OTHER,Org name,9 George Square,Glasgow,G2 1QQ,45,",
+ "OTHER,Org name,9 George Square,Glasgow,G2 1QQ,,000010",
+ "OTHER,Org name,9 George Square,Glasgow,,45,000010",
+ "OTHER,Org name,9 George Square,,G2 1QQ,45,000010",
+ "OTHER,Org name,,Glasgow,G2 1QQ,45,000010",
+ "OTHER,,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "null,Org name,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "INDIVIDUAL,Org name,9 George Square,Glasgow,null,45,000010",
+ "INDIVIDUAL,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "INDIVIDUAL,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "INDIVIDUAL,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "NON_LIMITED_COMPANY,Org name,9 George Square,Glasgow,null,45,000010",
+ "NON_LIMITED_COMPANY,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "NON_LIMITED_COMPANY,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "NON_LIMITED_COMPANY,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "LIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,45,null",
+ "LIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,null,000010",
+ "LIMITED_COMPANY,Org name,9 George Square,Glasgow,null,45,000010",
+ "LIMITED_COMPANY,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "LIMITED_COMPANY,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "LIMITED_COMPANY,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "UNLIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,45,null",
+ "UNLIMITED_COMPANY,Org name,9 George Square,Glasgow,G2 1QQ,null,000010",
+ "UNLIMITED_COMPANY,Org name,9 George Square,Glasgow,null,45,000010",
+ "UNLIMITED_COMPANY,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "UNLIMITED_COMPANY,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "UNLIMITED_COMPANY,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "REGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,null",
+ "REGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,null,000010",
+ "REGISTERED_CHARITY,Org name,9 George Square,Glasgow,null,45,000010",
+ "REGISTERED_CHARITY,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "REGISTERED_CHARITY,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "REGISTERED_CHARITY,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,null",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,null,000010",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,Glasgow,null,45,000010",
+ "UNREGISTERED_CHARITY,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "UNREGISTERED_CHARITY,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "UNREGISTERED_CHARITY,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,45,null",
+ "CHARITY,Org name,9 George Square,Glasgow,G2 1QQ,null,000010",
+ "CHARITY,Org name,9 George Square,Glasgow,null,45,000010",
+ "CHARITY,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "CHARITY,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "CHARITY,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ "OTHER,Org name,9 George Square,Glasgow,G2 1QQ,45,null",
+ "OTHER,Org name,9 George Square,Glasgow,G2 1QQ,null,000010",
+ "OTHER,Org name,9 George Square,Glasgow,null,45,000010",
+ "OTHER,Org name,9 George Square,null,G2 1QQ,45,000010",
+ "OTHER,Org name,null,Glasgow,G2 1QQ,45,000010",
+ "OTHER,null,9 George Square,Glasgow,G2 1QQ,45,000010",
+ }, nullValues = {"null"})
+ void returnsFalse(
+ final GrantApplicantOrganisationType type,
+ final String name,
+ final String addressLine1,
+ final String town,
+ final String postcode,
+ final String companiesHouseNumber,
+ final String charityCommissionNumber
+ ) {
+ final GrantApplicant applicant = GrantApplicant.builder()
+ .id(1)
+ .userId(APPLICANT_ID)
+ .build();
+ final GrantApplicantOrganisationProfile profile = GrantApplicantOrganisationProfile.builder()
+ .charityCommissionNumber(charityCommissionNumber)
+ .companiesHouseNumber(companiesHouseNumber)
+ .addressLine1(addressLine1)
+ .town(town)
+ .postcode(postcode)
+ .type(type)
+ .legalName(name)
+ .build();
+ applicant.setOrganisationProfile(profile);
+
+ when(grantApplicantService.getApplicantById(APPLICANT_ID)).thenReturn(applicant);
+
+ Boolean methodResponse = serviceUnderTest.isOrganisationComplete(APPLICANT_ID);
+
+ verify(grantApplicantService).getApplicantById(APPLICANT_ID);
+ assertFalse(methodResponse);
+ }
+
+ }
}
\ No newline at end of file
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileControllerTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileControllerTest.java
index b426604f..d26eb7c5 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileControllerTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantApplicantOrganisationProfileControllerTest.java
@@ -6,6 +6,7 @@
import gov.cabinetoffice.gap.applybackend.dto.api.UpdateGrantApplicantOrganisationProfileDto;
import gov.cabinetoffice.gap.applybackend.model.GrantApplicantOrganisationProfile;
import gov.cabinetoffice.gap.applybackend.service.GrantApplicantOrganisationProfileService;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
@@ -152,4 +153,37 @@ void updateOrganisation_UpdatesTheCorrectOrg() {
assertThat(methodResponse.getBody())
.isEqualTo(String.format("Organisation with ID %s has been updated.", grantApplicantOrganisationProfile.getId()));
}
+
+ @Nested
+ class IsOrganisationComplete {
+ @Test
+ void isOrganisationComplete_ReturnsTrue() {
+ final JwtPayload jwtPayload = JwtPayload.builder().sub(APPLICANT_USER_ID).build();
+ when(securityContext.getAuthentication()).thenReturn(authentication);
+ SecurityContextHolder.setContext(securityContext);
+ when(SecurityContextHolder.getContext().getAuthentication().getPrincipal()).thenReturn(jwtPayload);
+ when(grantApplicantOrganisationProfileService.isOrganisationComplete(APPLICANT_USER_ID)).thenReturn(true);
+
+ ResponseEntity response = controllerUnderTest.isOrganisationComplete();
+
+ verify(grantApplicantOrganisationProfileService).isOrganisationComplete(APPLICANT_USER_ID);
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(response.getBody(), true);
+ }
+
+ @Test
+ void isOrganisationComplete_ReturnsFalse() {
+ final JwtPayload jwtPayload = JwtPayload.builder().sub(APPLICANT_USER_ID).build();
+ when(securityContext.getAuthentication()).thenReturn(authentication);
+ SecurityContextHolder.setContext(securityContext);
+ when(SecurityContextHolder.getContext().getAuthentication().getPrincipal()).thenReturn(jwtPayload);
+ when(grantApplicantOrganisationProfileService.isOrganisationComplete(APPLICANT_USER_ID)).thenReturn(false);
+
+ ResponseEntity response = controllerUnderTest.isOrganisationComplete();
+
+ verify(grantApplicantOrganisationProfileService).isOrganisationComplete(APPLICANT_USER_ID);
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(response.getBody(), false);
+ }
+ }
}
\ No newline at end of file
From 533d481ddb416d50cc8bba6de9ece6dd3b3bf002 Mon Sep 17 00:00:00 2001
From: ryan-tco <135323857+ryan-tco@users.noreply.github.com>
Date: Fri, 24 Nov 2023 09:37:47 +0000
Subject: [PATCH 09/19] GAP-2257 Additional whitelisted chars (#63)
---
.../validation/validators/QuestionResponseValidator.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
index 65f12434..1ab6b844 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
@@ -216,7 +216,7 @@ private int getNumberOfWords(String response) {
}
private boolean containsSpecialCharacters(String response) {
- return !response.matches("^(?![\\s\\S])|^[a-zA-Z0-9à-üÀ-Ü\\s',!@£$%^&*()_+=\\[\\];./?><:\"{}|`~-]+$");
+ return !response.matches("^(?![\\s\\S])|^[a-zA-Z0-9à-üÀ-Ü\\s',!@£$%^&*()_+=\\[\\];./?><:\"{}|`~߀•–¥¢…µ-]+$");
}
private ValidationResult validateDate(final String[] dateComponents, final boolean isMandatory) {
From 7f92e2f92c9c487f4267cee2bfaae380d96549f0 Mon Sep 17 00:00:00 2001
From: dominicwest <101722961+dominicwest@users.noreply.github.com>
Date: Fri, 24 Nov 2023 13:14:33 +0000
Subject: [PATCH 10/19] Fixing infinite recursion issue (#64)
---
.../gap/applybackend/model/GrantAdvert.java | 2 ++
.../gap/applybackend/model/GrantApplication.java | 13 ++-----------
.../gap/applybackend/model/GrantScheme.java | 7 ++++++-
3 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java
index 68066b2e..59606fa5 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java
@@ -1,6 +1,7 @@
package gov.cabinetoffice.gap.applybackend.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonManagedReference;
import gov.cabinetoffice.gap.applybackend.enums.GrantAdvertStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -50,6 +51,7 @@ public class GrantAdvert extends BaseEntity {
@JoinColumn(name = "scheme_id", nullable = false)
@ToString.Exclude
@JsonIgnoreProperties({"hibernateLazyInitializer"})
+ @JsonManagedReference
private GrantScheme scheme;
@Column(name = "version", nullable = false)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
index 6343c2cd..c939ac8c 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
@@ -9,16 +9,7 @@
import lombok.ToString;
import org.hibernate.annotations.Type;
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
-import javax.persistence.GeneratedValue;
-import javax.persistence.GenerationType;
-import javax.persistence.Id;
-import javax.persistence.JoinColumn;
-import javax.persistence.OneToOne;
-import javax.persistence.Table;
+import javax.persistence.*;
import java.time.Instant;
@Entity
@@ -36,7 +27,7 @@ public class GrantApplication extends BaseEntity {
@Column(name = "grant_application_id")
private Integer id;
- @OneToOne
+ @OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "grant_scheme_id")
private GrantScheme grantScheme;
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
index ef154b30..a1e83a7b 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
@@ -1,5 +1,7 @@
package gov.cabinetoffice.gap.applybackend.model;
+import com.fasterxml.jackson.annotation.JsonBackReference;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.*;
import javax.persistence.*;
@@ -47,8 +49,11 @@ public class GrantScheme {
@Column(name = "scheme_contact")
private String email;
- @ToString.Exclude
@OneToMany(mappedBy = "scheme", orphanRemoval = true, cascade = CascadeType.ALL)
+ @ToString.Exclude
+ @JsonIgnoreProperties({ "hibernateLazyInitializer" })
+ @JsonBackReference
+ @Builder.Default
private List grantAdverts = new ArrayList<>();
@ToString.Exclude
From 3ff8b0e8458f855e08bd104927bdca0c929070e5 Mon Sep 17 00:00:00 2001
From: dominicwest <101722961+dominicwest@users.noreply.github.com>
Date: Fri, 24 Nov 2023 17:03:13 +0000
Subject: [PATCH 11/19] Fix one to one relationship (#65)
---
.../gap/applybackend/model/GrantAdvert.java | 1 -
.../gap/applybackend/model/GrantApplication.java | 11 +++--------
.../gap/applybackend/model/GrantScheme.java | 10 +++-------
.../gap/applybackend/service/GrantSchemeService.java | 9 ++++++++-
.../gap/applybackend/web/GrantSchemeController.java | 3 +--
.../applybackend/service/GrantSchemeServiceTest.java | 8 ++++----
.../applybackend/web/GrantSchemeControllerTest.java | 8 ++------
7 files changed, 21 insertions(+), 29 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java
index 59606fa5..208ae257 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantAdvert.java
@@ -34,7 +34,6 @@
@EntityListeners(AuditingEntityListener.class)
@Getter
@Setter
-@ToString
@NoArgsConstructor
@AllArgsConstructor
@Builder
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
index c939ac8c..de110472 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
@@ -1,12 +1,7 @@
package gov.cabinetoffice.gap.applybackend.model;
import gov.cabinetoffice.gap.applybackend.enums.GrantApplicantStatus;
-import lombok.AllArgsConstructor;
-import lombok.Builder;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import lombok.Setter;
-import lombok.ToString;
+import lombok.*;
import org.hibernate.annotations.Type;
import javax.persistence.*;
@@ -16,7 +11,6 @@
@Table(name = "grant_application")
@Getter
@Setter
-@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
@@ -27,7 +21,8 @@ public class GrantApplication extends BaseEntity {
@Column(name = "grant_application_id")
private Integer id;
- @OneToOne(fetch = FetchType.LAZY)
+ @ToString.Exclude
+ @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "grant_scheme_id")
private GrantScheme grantScheme;
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
index a1e83a7b..bafd8c76 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
@@ -1,7 +1,6 @@
package gov.cabinetoffice.gap.applybackend.model;
-import com.fasterxml.jackson.annotation.JsonBackReference;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;
import javax.persistence.*;
@@ -13,7 +12,6 @@
@Table(name = "grant_scheme")
@Getter
@Setter
-@ToString
@AllArgsConstructor
@NoArgsConstructor
@Builder
@@ -49,14 +47,12 @@ public class GrantScheme {
@Column(name = "scheme_contact")
private String email;
- @OneToMany(mappedBy = "scheme", orphanRemoval = true, cascade = CascadeType.ALL)
@ToString.Exclude
- @JsonIgnoreProperties({ "hibernateLazyInitializer" })
- @JsonBackReference
- @Builder.Default
+ @OneToMany(mappedBy = "scheme", orphanRemoval = true, cascade = CascadeType.ALL)
private List grantAdverts = new ArrayList<>();
@ToString.Exclude
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "grantScheme")
+ @JsonIgnore
private GrantApplication grantApplication;
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java
index f4c67c83..62d8fa6e 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeService.java
@@ -12,10 +12,17 @@ public class GrantSchemeService {
private final GrantSchemeRepository grantSchemeRepository;
- public GrantScheme getSchemeById(Integer schemeId) {
+ public GrantScheme getSchemeByIdWithApplicationAndAdverts(Integer schemeId) {
return grantSchemeRepository
.findByIdWithApplicationAndAdverts(schemeId)
.orElseThrow(() -> new NotFoundException(
String.format("No Grant Scheme with ID %s was found", schemeId)));
}
+
+ public GrantScheme getSchemeById(Integer schemeId) {
+ return grantSchemeRepository
+ .findById(schemeId)
+ .orElseThrow(() -> new NotFoundException(
+ String.format("No Grant Scheme with ID %s was found", schemeId)));
+ }
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java
index dabe75f0..c9265674 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeController.java
@@ -1,7 +1,6 @@
package gov.cabinetoffice.gap.applybackend.web;
import gov.cabinetoffice.gap.applybackend.dto.api.*;
-import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
import gov.cabinetoffice.gap.applybackend.mapper.GrantSchemeMapper;
import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
import gov.cabinetoffice.gap.applybackend.service.GrantAdvertService;
@@ -38,7 +37,7 @@ public class GrantSchemeController {
public ResponseEntity getGrantSchemeById(@PathVariable Integer grantSchemeId) {
final JwtPayload jwtPayload = (JwtPayload) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
- final GrantScheme grantScheme = grantSchemeService.getSchemeById(grantSchemeId);
+ final GrantScheme grantScheme = grantSchemeService.getSchemeByIdWithApplicationAndAdverts(grantSchemeId);
final GetGrantSchemeDto grantSchemeDto = new GetGrantSchemeDto(grantScheme);
final GetGrantApplicationDto grantApplicationDto = grantSchemeMapper.grantSchemeToGetGrantApplicationDto(grantScheme);
final List grantAdvertDtos = grantScheme.getGrantAdverts().stream()
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java
index 030dfc18..823d2d15 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantSchemeServiceTest.java
@@ -41,20 +41,20 @@ void getSchemeById_Success() {
.email("contact@contact.com")
.build();
- when(grantSchemeRepository.findByIdWithApplicationAndAdverts(SCHEME_ID)).thenReturn(Optional.of(scheme));
+ when(grantSchemeRepository.findById(SCHEME_ID)).thenReturn(Optional.of(scheme));
GrantScheme methodResponse = serviceUnderTest.getSchemeById(SCHEME_ID);
- verify(grantSchemeRepository).findByIdWithApplicationAndAdverts(SCHEME_ID);
+ verify(grantSchemeRepository).findById(SCHEME_ID);
assertEquals(methodResponse, scheme);
}
@Test
void getGrantSchemeById_OrgNotFound() {
- when(grantSchemeRepository.findByIdWithApplicationAndAdverts(SCHEME_ID)).thenReturn(Optional.empty());
+ when(grantSchemeRepository.findById(SCHEME_ID)).thenReturn(Optional.empty());
Exception result = assertThrows(NotFoundException.class, () -> serviceUnderTest.getSchemeById(SCHEME_ID));
- verify(grantSchemeRepository).findByIdWithApplicationAndAdverts(SCHEME_ID);
+ verify(grantSchemeRepository).findById(SCHEME_ID);
assertTrue(result.getMessage().contains("No Grant Scheme with ID "+ SCHEME_ID + " was found"));
}
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java
index e9c8b7e5..275c1d6b 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/web/GrantSchemeControllerTest.java
@@ -12,14 +12,11 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
-import org.modelmapper.ModelMapper;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -28,7 +25,6 @@
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -73,11 +69,11 @@ void getGrantSchemeById_ReturnsTheCorrectGrantScheme() {
.build();
final GetGrantSchemeDto getGrantSchemeDto = new GetGrantSchemeDto(grantScheme);
- when(grantSchemeService.getSchemeById(SCHEME_ID)).thenReturn(grantScheme);
+ when(grantSchemeService.getSchemeByIdWithApplicationAndAdverts(SCHEME_ID)).thenReturn(grantScheme);
ResponseEntity response = controllerUnderTest.getGrantSchemeById(SCHEME_ID);
- verify(grantSchemeService).getSchemeById(SCHEME_ID);
+ verify(grantSchemeService).getSchemeByIdWithApplicationAndAdverts(SCHEME_ID);
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(GetGrantSchemeWithApplicationAndAdverts.builder()
.grantScheme(getGrantSchemeDto)
From 19487635cd3a5bb916939c712906c9fddbb9f227 Mon Sep 17 00:00:00 2001
From: dominicwest <101722961+dominicwest@users.noreply.github.com>
Date: Mon, 27 Nov 2023 15:10:58 +0000
Subject: [PATCH 12/19] GAP-2309: Fixing v1 schemes from blowing up (#66)
---
.../validation/validators/QuestionResponseValidator.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
index 1ab6b844..0b843bda 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
@@ -139,7 +139,7 @@ private ValidationResult validate(CreateQuestionResponseDto submittedQuestion, S
}
}
- if(containsSpecialCharacters(submittedQuestion.getResponse())) {
+ if (!singleResponseIsEmpty && containsSpecialCharacters(submittedQuestion.getResponse())) {
result.addError(ValidationConstants.SINGLE_RESPONSE_FIELD, "Answer must only include letters, numbers, and special characters such as hyphens, spaces and apostrophes");
return result;
}
From a297e61ec44afe9ba3f0c59dfe10325b46bd88db Mon Sep 17 00:00:00 2001
From: dominicwest <101722961+dominicwest@users.noreply.github.com>
Date: Mon, 27 Nov 2023 17:07:21 +0000
Subject: [PATCH 13/19] GAP-2311: Fixing v1 applications (#67)
---
.../gap/applybackend/model/GrantApplication.java | 4 +++-
.../gap/applybackend/model/GrantScheme.java | 5 +++--
.../repository/GrantApplicationRepository.java | 10 ++++++++++
3 files changed, 16 insertions(+), 3 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
index de110472..ae9a31ef 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantApplication.java
@@ -1,5 +1,6 @@
package gov.cabinetoffice.gap.applybackend.model;
+import com.fasterxml.jackson.annotation.JsonManagedReference;
import gov.cabinetoffice.gap.applybackend.enums.GrantApplicantStatus;
import lombok.*;
import org.hibernate.annotations.Type;
@@ -22,8 +23,9 @@ public class GrantApplication extends BaseEntity {
private Integer id;
@ToString.Exclude
- @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
+ @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JoinColumn(name = "grant_scheme_id")
+ @JsonManagedReference
private GrantScheme grantScheme;
@Column(name = "version")
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
index bafd8c76..4d6cf04b 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/model/GrantScheme.java
@@ -1,6 +1,6 @@
package gov.cabinetoffice.gap.applybackend.model;
-import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.*;
import javax.persistence.*;
@@ -49,10 +49,11 @@ public class GrantScheme {
@ToString.Exclude
@OneToMany(mappedBy = "scheme", orphanRemoval = true, cascade = CascadeType.ALL)
+ @JsonBackReference
private List grantAdverts = new ArrayList<>();
@ToString.Exclude
@OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "grantScheme")
- @JsonIgnore
+ @JsonBackReference
private GrantApplication grantApplication;
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantApplicationRepository.java b/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantApplicationRepository.java
index 1feaeb50..09378a60 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantApplicationRepository.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/repository/GrantApplicationRepository.java
@@ -3,7 +3,10 @@
import gov.cabinetoffice.gap.applybackend.model.GrantApplication;
import gov.cabinetoffice.gap.applybackend.model.GrantScheme;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
import java.util.Optional;
@@ -11,5 +14,12 @@ public interface GrantApplicationRepository extends JpaRepository getGrantApplicationByGrantSchemeId(int schemeId);
Optional findByGrantScheme(GrantScheme grantScheme);
+
+
+ @NotNull
+ @EntityGraph(attributePaths = {"grantScheme"})
+ @Query("select g from GrantApplication g where g.id = ?1")
+ @Override
+ Optional findById(@NotNull Integer integer);
}
From 536cb0a8ad1e728c686fd3b92f69dadacc223ab8 Mon Sep 17 00:00:00 2001
From: dominicwest <101722961+dominicwest@users.noreply.github.com>
Date: Wed, 29 Nov 2023 12:53:19 +0000
Subject: [PATCH 14/19] TMI-466: Fix enum mistmatch (#68)
---
.../enums/GrantMandatoryQuestionFundingLocation.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionFundingLocation.java b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionFundingLocation.java
index 5c2749f0..4dc3787b 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionFundingLocation.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/enums/GrantMandatoryQuestionFundingLocation.java
@@ -8,7 +8,7 @@ public enum GrantMandatoryQuestionFundingLocation {
YORKSHIRE_AND_THE_HUMBER("Yorkshire and the Humber"),
EAST_MIDLANDS_ENGLAND("East Midlands (England)"),
WEST_MIDLANDS("West Midlands (England)"),
- EAST_ENGLAND("East England"),
+ EAST_ENGLAND("East (England)"),
LONDON("London"),
SOUTH_EAST_ENGLAND("South East (England)"),
SOUTH_WEST_ENGLAND("South West (England)"),
From b2e2b243954c2ffc0bfb7fdbc35b80ad0ae65787 Mon Sep 17 00:00:00 2001
From: ryan-tco <135323857+ryan-tco@users.noreply.github.com>
Date: Wed, 29 Nov 2023 13:55:44 +0000
Subject: [PATCH 15/19] GAP-2257: Additional Whitelisted Chars (#69)
---
.../validation/validators/QuestionResponseValidator.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
index 0b843bda..17d3fb76 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/validation/validators/QuestionResponseValidator.java
@@ -216,7 +216,7 @@ private int getNumberOfWords(String response) {
}
private boolean containsSpecialCharacters(String response) {
- return !response.matches("^(?![\\s\\S])|^[a-zA-Z0-9à-üÀ-Ü\\s',!@£$%^&*()_+=\\[\\];./?><:\"{}|`~߀•–¥¢…µ-]+$");
+ return !response.matches("^(?![\\s\\S])|^[a-zA-Z0-9à-üÀ-Ü\\s',!@£$%^&*()_+=\\[\\];./?><:\"{}|`~߀•–¥¢…µèéêëěẽýŷÿùúûüǔũūűìíîïǐĩiòóôöǒàáâäśğźžżćçčċñńņň-]+$");
}
private ValidationResult validateDate(final String[] dateComponents, final boolean isMandatory) {
From 18908ca3847961010e0d855adc1d0b122a8c5ce7 Mon Sep 17 00:00:00 2001
From: a-lor-cab <107372333+a-lor-cab@users.noreply.github.com>
Date: Thu, 30 Nov 2023 15:09:01 +0000
Subject: [PATCH 16/19] add status to the dto, and modify the mapper to
accomodate it (#70)
---
.../applybackend/dto/api/GetGrantMandatoryQuestionDto.java | 2 ++
.../applybackend/mapper/GrantMandatoryQuestionMapper.java | 7 +++++++
.../mapper/GrantMandatoryQuestionMapperTest.java | 3 +++
3 files changed, 12 insertions(+)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantMandatoryQuestionDto.java b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantMandatoryQuestionDto.java
index c890d34f..980d481a 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantMandatoryQuestionDto.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantMandatoryQuestionDto.java
@@ -40,4 +40,6 @@ public class GetGrantMandatoryQuestionDto {
private String fundingAmount;
private List fundingLocation;
+
+ private String status;
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapper.java b/src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapper.java
index 13dc185f..3a279af1 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapper.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapper.java
@@ -4,6 +4,7 @@
import gov.cabinetoffice.gap.applybackend.dto.api.UpdateGrantMandatoryQuestionDto;
import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionFundingLocation;
import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionOrgType;
+import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionStatus;
import gov.cabinetoffice.gap.applybackend.model.GrantMandatoryQuestions;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@@ -27,8 +28,14 @@ public interface GrantMandatoryQuestionMapper {
@Mapping(source = "fundingAmount", target = "fundingAmount", qualifiedByName = "mapEntityFundingAmountToDtoFundingAmount")
@Mapping(source = "fundingLocation", target = "fundingLocation", qualifiedByName = "mapEntityFundingLocationToDtoFundingLocation")
@Mapping(source = "submission.id", target = "submissionId")
+ @Mapping(source = "status", target = "status", qualifiedByName = "mapEntityStatusToDtoStatus")
GetGrantMandatoryQuestionDto mapGrantMandatoryQuestionToGetGrantMandatoryQuestionDTO(GrantMandatoryQuestions source);
+ @Named("mapEntityStatusToDtoStatus")
+ default String mapEntityStatusToDtoStatus(GrantMandatoryQuestionStatus status) {
+ return status.toString();
+ }
+
@Named("mapEntityOrgTypeToDtoOrgType")
default String mapEntityOrgTypeToDtoOrgType(GrantMandatoryQuestionOrgType type) {
return type.toString();
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapperTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapperTest.java
index 10566093..43c3fbb5 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapperTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/mapper/GrantMandatoryQuestionMapperTest.java
@@ -4,6 +4,7 @@
import gov.cabinetoffice.gap.applybackend.dto.api.UpdateGrantMandatoryQuestionDto;
import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionFundingLocation;
import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionOrgType;
+import gov.cabinetoffice.gap.applybackend.enums.GrantMandatoryQuestionStatus;
import gov.cabinetoffice.gap.applybackend.model.GrantMandatoryQuestions;
import gov.cabinetoffice.gap.applybackend.model.Submission;
import org.junit.jupiter.api.Nested;
@@ -33,6 +34,7 @@ void grantMandatoryQuestionIsFilled() {
.submission(submission)
.addressLine1("addressLine1")
.addressLine2("addressLine2")
+ .status(GrantMandatoryQuestionStatus.IN_PROGRESS)
.city("city")
.county("county")
.postcode("postcode")
@@ -57,6 +59,7 @@ void grantMandatoryQuestionIsFilled() {
assertThat(result.getFundingAmount()).isEqualTo(grantMandatoryQuestions.getFundingAmount().toString());
assertThat(result.getFundingLocation()).isEqualTo(List.of(grantMandatoryQuestions.getFundingLocation()[0].getName()));
assertThat(result.getSubmissionId()).isEqualTo(uuid);
+ assertThat(result.getStatus()).isEqualTo(grantMandatoryQuestions.getStatus().toString());
}
@Test
From 63eed52676df604545a8b82bf15b32837eb14918 Mon Sep 17 00:00:00 2001
From: iaincooper-tco <99728291+iaincooper-tco@users.noreply.github.com>
Date: Sun, 3 Dec 2023 21:58:24 +0000
Subject: [PATCH 17/19] TMI2-484: Fix GAP ID Generation (#73)
---
.../GrantMandatoryQuestionService.java | 4 +-
.../service/SubmissionService.java | 22 ++++++----
.../applybackend/utils/GapIdGenerator.java | 6 +--
.../GrantMandatoryQuestionServiceTest.java | 34 +++++----------
.../service/SubmissionServiceTest.java | 42 +++++++++++++++++--
5 files changed, 66 insertions(+), 42 deletions(-)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
index a7510f4c..69482d76 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionService.java
@@ -95,9 +95,7 @@ public GrantMandatoryQuestions createMandatoryQuestion(GrantScheme scheme, Grant
public GrantMandatoryQuestions updateMandatoryQuestion(GrantMandatoryQuestions grantMandatoryQuestions, GrantApplicant grantApplicant) {
if (grantMandatoryQuestions.getStatus().equals(GrantMandatoryQuestionStatus.COMPLETED)) {
- final Submission submission = grantMandatoryQuestions.getSubmission();
- final String gapId = submission == null ? GapIdGenerator
- .generateGapId(grantApplicant.getId(), envProperties.getEnvironmentName(), grantMandatoryQuestionRepository.count(), true) : submission.getGapId();
+ final String gapId = GapIdGenerator.generateGapId(grantApplicant.getId(), envProperties.getEnvironmentName(), grantMandatoryQuestionRepository.count(), 2);
grantMandatoryQuestions.setGapId(gapId);
}
return grantMandatoryQuestionRepository
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java
index a4a1ab31..032431ea 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/SubmissionService.java
@@ -221,17 +221,21 @@ public void submit(final Submission submission, final GrantApplicant grantApplic
}
final long diligenceCheckRecordsFromToday = getDiligenceCheckRecordsCountFromToday();
+ final int version = submission.getScheme().getVersion();
- final String gapId = GapIdGenerator.generateGapId(
- grantApplicant.getId(),
- envProperties.getEnvironmentName(),
- diligenceCheckRecordsFromToday + 1,
- false
- );
- submission.setGapId(gapId);
- if (submission.getScheme().getVersion() > 1) {
- setMandatoryQuestionsGapId(submission);
+ final Optional grantMandatoryQuestion = grantMandatoryQuestionRepository.findBySubmissionId(submission.getId());
+ final String gapId;
+ if (grantMandatoryQuestion.isPresent()) {
+ gapId = grantMandatoryQuestion.get().getGapId();
+ } else {
+ gapId = GapIdGenerator.generateGapId(
+ grantApplicant.getId(),
+ envProperties.getEnvironmentName(),
+ diligenceCheckRecordsFromToday + 1,
+ version
+ );
}
+ submission.setGapId(gapId);
submitApplication(submission);
notifyClient.sendConfirmationEmail(emailAddress, submission);
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/utils/GapIdGenerator.java b/src/main/java/gov/cabinetoffice/gap/applybackend/utils/GapIdGenerator.java
index 4b385d9f..d4b643c4 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/utils/GapIdGenerator.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/utils/GapIdGenerator.java
@@ -5,7 +5,7 @@
public class GapIdGenerator {
- public static String generateGapId(final Long userId, final String env, final long recordNumber, final boolean isMandatoryQuestion) {
+ public static String generateGapId(final Long userId, final String env, final long recordNumber, final int version) {
final LocalDate currentDate = LocalDate.now();
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
final String date = currentDate.format(formatter);
@@ -13,10 +13,10 @@ public static String generateGapId(final Long userId, final String env, final lo
return "GAP" +
"-" +
env +
- (isMandatoryQuestion ?
- "-MQ-" : "-") +
+ "-" +
date +
"-" +
+ version +
recordNumber +
"-" +
userId
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
index c2e44e06..f37c9695 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantMandatoryQuestionServiceTest.java
@@ -21,6 +21,8 @@
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Stream;
@@ -381,6 +383,11 @@ void updateMandatoryQuestion_UpdatesExpectedMandatoryQuestions() {
@Test
void updateMandatoryQuestion_UpdatesExpectedMandatoryQuestionsAndSetsGapId() {
final UUID mandatoryQuestionsId = UUID.randomUUID();
+
+ final LocalDate currentDate = LocalDate.now();
+ final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+ final String date = currentDate.format(formatter);
+
final GrantMandatoryQuestions grantMandatoryQuestions = GrantMandatoryQuestions
.builder()
.id(mandatoryQuestionsId)
@@ -398,31 +405,10 @@ void updateMandatoryQuestion_UpdatesExpectedMandatoryQuestionsAndSetsGapId() {
verify(grantMandatoryQuestionRepository).save(grantMandatoryQuestions);
assertThat(methodResponse).isEqualTo(grantMandatoryQuestions);
- assertThat(methodResponse.getGapId()).contains("GAP-local-MQ-");
- assertThat(methodResponse.getGapId()).isEqualTo(grantMandatoryQuestions.getGapId());
- }
- @Test
- void updateMandatoryQuestion_UpdatesExpectedMandatoryQuestionsAndSetsGapIdBySubmission() {
- final UUID mandatoryQuestionsId = UUID.randomUUID();
- final Submission submission = Submission.builder().gapId("GAP-ID").build();
- final GrantMandatoryQuestions grantMandatoryQuestions = GrantMandatoryQuestions
- .builder()
- .id(mandatoryQuestionsId)
- .status(GrantMandatoryQuestionStatus.COMPLETED)
- .submission(submission)
- .build();
-
- when(grantMandatoryQuestionRepository.findById(mandatoryQuestionsId))
- .thenReturn(Optional.of(grantMandatoryQuestions));
- when(grantMandatoryQuestionRepository.save(grantMandatoryQuestions))
- .thenReturn(grantMandatoryQuestions);
-
- final GrantMandatoryQuestions methodResponse = serviceUnderTest.updateMandatoryQuestion(grantMandatoryQuestions, grantApplicant);
-
- verify(grantMandatoryQuestionRepository).save(grantMandatoryQuestions);
- assertThat(methodResponse).isEqualTo(grantMandatoryQuestions);
- assertThat(methodResponse.getGapId()).isEqualTo(submission.getGapId());
+ //GAP ID Should be GAP-{environment}-{date}-{version}{recordNumber}-{userId}
+ assertThat(methodResponse.getGapId()).isEqualTo("GAP-"+ "local" + "-" + date + "-22-1");
+ assertThat(methodResponse.getGapId()).isEqualTo(grantMandatoryQuestions.getGapId());
}
}
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/SubmissionServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/SubmissionServiceTest.java
index c664b7c9..f0ede555 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/SubmissionServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/SubmissionServiceTest.java
@@ -31,6 +31,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.*;
+import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -1094,8 +1095,9 @@ void submit_CreatesGrantBeneficiary() {
}
@Test
- void submit_SubmitsTheApplicationFormAndUpdatesMandatoryQuestions() {
+ void submit_SubmitsTheApplicationFormAndTakesIDFromMandatoryQuestions() {
final String emailAddress = "test@email.com";
+ final String gapId = "GAP-local-20231201-21-1";
final ArgumentCaptor submissionCaptor = ArgumentCaptor.forClass(Submission.class);
final GrantApplicant grantApplicant = GrantApplicant.builder()
.userId(userId)
@@ -1107,7 +1109,7 @@ void submit_SubmitsTheApplicationFormAndUpdatesMandatoryQuestions() {
final GrantMandatoryQuestions grantMandatoryQuestions = GrantMandatoryQuestions.builder()
.id(UUID.randomUUID())
- .gapId(null)
+ .gapId(gapId)
.build();
submission.setScheme(scheme);
@@ -1122,7 +1124,41 @@ void submit_SubmitsTheApplicationFormAndUpdatesMandatoryQuestions() {
final Submission capturedSubmission = submissionCaptor.getValue();
- assertThat(grantMandatoryQuestions.getGapId()).isEqualTo(capturedSubmission.getGapId());
+ assertThat(grantMandatoryQuestions.getGapId()).isEqualTo(gapId);
+ assertThat(capturedSubmission.getGapId()).isEqualTo(gapId);
+ }
+
+ @Test
+ void submit_SubmitsTheApplicationFormAndGeneratesID() {
+ final LocalDate currentDate = LocalDate.now();
+ final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
+ final String date = currentDate.format(formatter);
+
+ final String emailAddress = "test@email.com";
+ final String gapId = "GAP-LOCAL-" + date +"-12-1";
+ final ArgumentCaptor submissionCaptor = ArgumentCaptor.forClass(Submission.class);
+ final GrantApplicant grantApplicant = GrantApplicant.builder()
+ .userId(userId)
+ .id(1)
+ .build();
+ final GrantScheme scheme = GrantScheme.builder()
+ .version(1)
+ .build();
+
+ submission.setScheme(scheme);
+
+ when(grantMandatoryQuestionRepository.findBySubmissionId(submission.getId())).thenReturn(Optional.empty());
+ when(diligenceCheckRepository.countDistinctByApplicationNumberContains(any())).thenReturn(1L);
+ doReturn(true).when(serviceUnderTest).isSubmissionReadyToBeSubmitted(userId, SUBMISSION_ID);
+
+ serviceUnderTest.submit(submission, grantApplicant, emailAddress);
+
+ verify(notifyClient).sendConfirmationEmail(emailAddress, submission);
+ verify(submissionRepository).save(submissionCaptor.capture());
+
+ final Submission capturedSubmission = submissionCaptor.getValue();
+
+ assertThat(capturedSubmission.getGapId()).isEqualTo(gapId);
}
}
From cacf30237d1989e7a6cf03f5669685084c386704 Mon Sep 17 00:00:00 2001
From: jimpurvisTCO <151734116+jimpurvisTCO@users.noreply.github.com>
Date: Mon, 4 Dec 2023 09:53:49 +0000
Subject: [PATCH 18/19] TMI2-479 -Adding 'isPublished' property to grant advert
DTOs (#71)
* TMI2-479 -Adding 'isPublished' property to grant advert DTOs
---------
Co-authored-by: Jim Purvis
---
.../dto/api/GetGrantAdvertDto.java | 2 +
.../service/GrantAdvertService.java | 2 +
.../service/GrantAdvertServiceTest.java | 96 +++++++++++++++++++
3 files changed, 100 insertions(+)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java
index c00bf88f..ff6d7de4 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java
@@ -31,4 +31,6 @@ public class GetGrantAdvertDto {
private boolean isAdvertInDatabase;
private GetGrantMandatoryQuestionDto mandatoryQuestionsDto;
+
+ private boolean isPublished;
}
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java
index 3aa4d868..4130d119 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertService.java
@@ -7,6 +7,7 @@
import com.contentful.java.cda.CDAResourceNotFoundException;
import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantAdvertDto;
import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantMandatoryQuestionDto;
+import gov.cabinetoffice.gap.applybackend.enums.GrantAdvertStatus;
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
import gov.cabinetoffice.gap.applybackend.mapper.GrantMandatoryQuestionMapper;
import gov.cabinetoffice.gap.applybackend.model.GrantAdvert;
@@ -63,6 +64,7 @@ public GetGrantAdvertDto generateGetGrantAdvertDto(GrantAdvert advert, GetGrantM
.grantSchemeId(advert.getScheme().getId())
.isAdvertInDatabase(true)
.mandatoryQuestionsDto(mandatoryQuestions)
+ .isPublished(advert.getStatus() == GrantAdvertStatus.PUBLISHED)
.build();
}
diff --git a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertServiceTest.java b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertServiceTest.java
index 3cd6a757..acb645a5 100644
--- a/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertServiceTest.java
+++ b/src/test/java/gov/cabinetoffice/gap/applybackend/service/GrantAdvertServiceTest.java
@@ -8,6 +8,7 @@
import com.contentful.java.cda.FetchQuery;
import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantAdvertDto;
import gov.cabinetoffice.gap.applybackend.dto.api.GetGrantMandatoryQuestionDto;
+import gov.cabinetoffice.gap.applybackend.enums.GrantAdvertStatus;
import gov.cabinetoffice.gap.applybackend.exception.NotFoundException;
import gov.cabinetoffice.gap.applybackend.model.GrantAdvert;
import gov.cabinetoffice.gap.applybackend.model.GrantAdvertPageResponse;
@@ -149,6 +150,7 @@ void generateGetGrantAdvertDto_createDtoForInternalApplicationAndVersion1() {
.version(1)
.scheme(scheme)
.response(response)
+ .status(GrantAdvertStatus.PUBLISHED)
.build();
final GetGrantMandatoryQuestionDto mandatoryQuestionDto = GetGrantMandatoryQuestionDto.builder().build();
@@ -164,6 +166,7 @@ void generateGetGrantAdvertDto_createDtoForInternalApplicationAndVersion1() {
assertThat(methodResponse.getGrantApplicationId()).isEqualTo(1);
assertThat(methodResponse.getGrantSchemeId()).isEqualTo(1);
assertThat(methodResponse.getMandatoryQuestionsDto()).isEqualTo(mandatoryQuestionDto);
+ assertThat(methodResponse.isPublished()).isTrue();
}
@Test
@@ -176,6 +179,7 @@ void generateGetGrantAdvertDto_createDtoForInternalApplicationAndVersion2() {
.version(2)
.scheme(scheme)
.response(response)
+ .status(GrantAdvertStatus.PUBLISHED)
.build();
final GetGrantMandatoryQuestionDto mandatoryQuestionDto = GetGrantMandatoryQuestionDto.builder().build();
@@ -191,6 +195,7 @@ void generateGetGrantAdvertDto_createDtoForInternalApplicationAndVersion2() {
assertThat(methodResponse.getGrantApplicationId()).isEqualTo(1);
assertThat(methodResponse.getGrantSchemeId()).isEqualTo(1);
assertThat(methodResponse.getMandatoryQuestionsDto()).isEqualTo(mandatoryQuestionDto);
+ assertThat(methodResponse.isPublished()).isTrue();
}
@Test
@@ -203,6 +208,7 @@ void generateGetGrantAdvertDto_createDtoForExternalApplicationAndVersion2() {
.version(2)
.scheme(scheme)
.response(response)
+ .status(GrantAdvertStatus.PUBLISHED)
.build();
final GetGrantMandatoryQuestionDto mandatoryQuestionDto = GetGrantMandatoryQuestionDto.builder().build();
@@ -218,6 +224,94 @@ void generateGetGrantAdvertDto_createDtoForExternalApplicationAndVersion2() {
assertThat(methodResponse.getGrantApplicationId()).isNull();
assertThat(methodResponse.getGrantSchemeId()).isEqualTo(1);
assertThat(methodResponse.getMandatoryQuestionsDto()).isEqualTo(mandatoryQuestionDto);
+ assertThat(methodResponse.isPublished()).isTrue();
+ }
+
+ @Test
+ void generateGetGrantAdvertDto_createDtoForDraftExternalApplicationAndVersion2() {
+ final GrantAdvertResponse response = generateResponseWithHowToApplySection();
+ final GrantScheme scheme = GrantScheme.builder().id(1).build();
+ final GrantAdvert advert = GrantAdvert.builder()
+ .contentfulSlug("slug")
+ .id(ADVERT_ID)
+ .version(2)
+ .scheme(scheme)
+ .response(response)
+ .status(GrantAdvertStatus.DRAFT)
+ .build();
+ final GetGrantMandatoryQuestionDto mandatoryQuestionDto = GetGrantMandatoryQuestionDto.builder().build();
+
+ when(grantApplicationService.doesSchemeHaveApplication(scheme)).thenReturn(false);
+ when(grantApplicationService.getGrantApplicationId(scheme)).thenReturn(null);
+
+ final GetGrantAdvertDto methodResponse = grantAdvertService.generateGetGrantAdvertDto(advert, mandatoryQuestionDto);
+
+ assertThat(methodResponse.getId()).isEqualTo(ADVERT_ID);
+ assertThat(methodResponse.getVersion()).isEqualTo(2);
+ assertThat(methodResponse.getExternalSubmissionUrl()).isEqualTo("responseUrl");
+ assertThat(methodResponse.isInternal()).isFalse();
+ assertThat(methodResponse.getGrantApplicationId()).isNull();
+ assertThat(methodResponse.getGrantSchemeId()).isEqualTo(1);
+ assertThat(methodResponse.getMandatoryQuestionsDto()).isEqualTo(mandatoryQuestionDto);
+ assertThat(methodResponse.isPublished()).isFalse();
+ }
+
+ @Test
+ void generateGetGrantAdvertDto_createDtoForUnpublishedExternalApplicationAndVersion2() {
+ final GrantAdvertResponse response = generateResponseWithHowToApplySection();
+ final GrantScheme scheme = GrantScheme.builder().id(1).build();
+ final GrantAdvert advert = GrantAdvert.builder()
+ .contentfulSlug("slug")
+ .id(ADVERT_ID)
+ .version(2)
+ .scheme(scheme)
+ .response(response)
+ .status(GrantAdvertStatus.UNPUBLISHED)
+ .build();
+ final GetGrantMandatoryQuestionDto mandatoryQuestionDto = GetGrantMandatoryQuestionDto.builder().build();
+
+ when(grantApplicationService.doesSchemeHaveApplication(scheme)).thenReturn(false);
+ when(grantApplicationService.getGrantApplicationId(scheme)).thenReturn(null);
+
+ final GetGrantAdvertDto methodResponse = grantAdvertService.generateGetGrantAdvertDto(advert, mandatoryQuestionDto);
+
+ assertThat(methodResponse.getId()).isEqualTo(ADVERT_ID);
+ assertThat(methodResponse.getVersion()).isEqualTo(2);
+ assertThat(methodResponse.getExternalSubmissionUrl()).isEqualTo("responseUrl");
+ assertThat(methodResponse.isInternal()).isFalse();
+ assertThat(methodResponse.getGrantApplicationId()).isNull();
+ assertThat(methodResponse.getGrantSchemeId()).isEqualTo(1);
+ assertThat(methodResponse.getMandatoryQuestionsDto()).isEqualTo(mandatoryQuestionDto);
+ assertThat(methodResponse.isPublished()).isFalse();
+ }
+
+ @Test
+ void generateGetGrantAdvertDto_createDtoForScheduledExternalApplicationAndVersion2() {
+ final GrantAdvertResponse response = generateResponseWithHowToApplySection();
+ final GrantScheme scheme = GrantScheme.builder().id(1).build();
+ final GrantAdvert advert = GrantAdvert.builder()
+ .contentfulSlug("slug")
+ .id(ADVERT_ID)
+ .version(2)
+ .scheme(scheme)
+ .response(response)
+ .status(GrantAdvertStatus.SCHEDULED)
+ .build();
+ final GetGrantMandatoryQuestionDto mandatoryQuestionDto = GetGrantMandatoryQuestionDto.builder().build();
+
+ when(grantApplicationService.doesSchemeHaveApplication(scheme)).thenReturn(false);
+ when(grantApplicationService.getGrantApplicationId(scheme)).thenReturn(null);
+
+ final GetGrantAdvertDto methodResponse = grantAdvertService.generateGetGrantAdvertDto(advert, mandatoryQuestionDto);
+
+ assertThat(methodResponse.getId()).isEqualTo(ADVERT_ID);
+ assertThat(methodResponse.getVersion()).isEqualTo(2);
+ assertThat(methodResponse.getExternalSubmissionUrl()).isEqualTo("responseUrl");
+ assertThat(methodResponse.isInternal()).isFalse();
+ assertThat(methodResponse.getGrantApplicationId()).isNull();
+ assertThat(methodResponse.getGrantSchemeId()).isEqualTo(1);
+ assertThat(methodResponse.getMandatoryQuestionsDto()).isEqualTo(mandatoryQuestionDto);
+ assertThat(methodResponse.isPublished()).isFalse();
}
@Test
@@ -230,6 +324,7 @@ void generateGetGrantAdvertDto_createDtoForExternalApplicationAndVersion1() {
.version(1)
.scheme(scheme)
.response(response)
+ .status(GrantAdvertStatus.PUBLISHED)
.build();
final GetGrantMandatoryQuestionDto mandatoryQuestionDto = GetGrantMandatoryQuestionDto.builder().build();
@@ -245,6 +340,7 @@ void generateGetGrantAdvertDto_createDtoForExternalApplicationAndVersion1() {
assertThat(methodResponse.getGrantApplicationId()).isNull();
assertThat(methodResponse.getGrantSchemeId()).isEqualTo(1);
assertThat(methodResponse.getMandatoryQuestionsDto()).isEqualTo(mandatoryQuestionDto);
+ assertThat(methodResponse.isPublished()).isTrue();
}
}
From b04744125b321c6af1c1636d360f8eb208fcb5e6 Mon Sep 17 00:00:00 2001
From: iaincooper-tco <99728291+iaincooper-tco@users.noreply.github.com>
Date: Mon, 4 Dec 2023 12:34:10 +0000
Subject: [PATCH 19/19] TMI2-479: Fix isPublished having wrong key in response
(#75)
---
.../gap/applybackend/dto/api/GetGrantAdvertDto.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java
index ff6d7de4..272560fe 100644
--- a/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java
+++ b/src/main/java/gov/cabinetoffice/gap/applybackend/dto/api/GetGrantAdvertDto.java
@@ -32,5 +32,6 @@ public class GetGrantAdvertDto {
private GetGrantMandatoryQuestionDto mandatoryQuestionsDto;
+ @JsonProperty("isPublished")
private boolean isPublished;
}