diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/configuration/ExceptionMap.java b/src/main/java/it/gov/pagopa/onboarding/citizen/configuration/ExceptionMap.java index 61cda9e..1187e1a 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/configuration/ExceptionMap.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/configuration/ExceptionMap.java @@ -26,6 +26,14 @@ public ExceptionMap() { message ) ); + + exceptions.put(CitizenConstants.ExceptionName.TPP_NOT_FOUND, message -> + new ClientExceptionWithBody( + HttpStatus.NOT_FOUND, + CitizenConstants.ExceptionCode.TPP_NOT_FOUND, + message + ) + ); } public RuntimeException throwException(String exceptionKey, String message) { diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/connector/tpp/TppConnector.java b/src/main/java/it/gov/pagopa/onboarding/citizen/connector/tpp/TppConnector.java new file mode 100644 index 0000000..a712bf1 --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/connector/tpp/TppConnector.java @@ -0,0 +1,8 @@ +package it.gov.pagopa.onboarding.citizen.connector.tpp; + +import it.gov.pagopa.onboarding.citizen.dto.TppDTO; +import reactor.core.publisher.Mono; + +public interface TppConnector { + Mono get(String tppId); +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/connector/tpp/TppConnectorImpl.java b/src/main/java/it/gov/pagopa/onboarding/citizen/connector/tpp/TppConnectorImpl.java new file mode 100644 index 0000000..d3f09d7 --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/connector/tpp/TppConnectorImpl.java @@ -0,0 +1,27 @@ +package it.gov.pagopa.onboarding.citizen.connector.tpp; + +import it.gov.pagopa.onboarding.citizen.dto.TppDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; + +@Service +public class TppConnectorImpl implements TppConnector { + private final WebClient webClient; + + public TppConnectorImpl(WebClient.Builder webClientBuilder, + @Value("${rest-client.tpp.baseUrl}") String baseUrl) { + this.webClient = webClientBuilder.baseUrl(baseUrl).build(); + } + + @Override + public Mono get(String tppId) { + return webClient.get() + .uri("/emd/tpp/" + tppId) + .retrieve() + .bodyToMono(new ParameterizedTypeReference<>() { + }); + } +} diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/constants/CitizenConstants.java b/src/main/java/it/gov/pagopa/onboarding/citizen/constants/CitizenConstants.java index 349f395..0c80794 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/constants/CitizenConstants.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/constants/CitizenConstants.java @@ -5,6 +5,8 @@ public static final class ExceptionCode { public static final String CITIZEN_NOT_ONBOARDED = "CITIZEN_NOT_ONBOARDED"; public static final String GENERIC_ERROR = "GENERIC_ERROR"; + public static final String TPP_NOT_FOUND = "TPP_NOT_FOUND"; + private ExceptionCode() {} } @@ -19,9 +21,18 @@ public static final class ExceptionName { public static final String CITIZEN_NOT_ONBOARDED = "CITIZEN_NOT_ONBOARDED"; public static final String GENERIC_ERROR = "GENERIC_ERROR"; + public static final String TPP_NOT_FOUND = "TPP_NOT_FOUND"; + private ExceptionName() {} } + public static final class ValidationRegex { + + public static final String FISCAL_CODE_STRUCTURE_REGEX = "(^([A-Za-z]{6}[0-9lmnpqrstuvLMNPQRSTUV]{2}[abcdehlmprstABCDEHLMPRST][0-9lmnpqrstuvLMNPQRSTUV]{2}[A-Za-z][0-9lmnpqrstuvLMNPQRSTUV]{3}[A-Za-z])$)|(^(\\d{11})$)"; + + private ValidationRegex() {} + } + private CitizenConstants() {} } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenController.java b/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenController.java index 505f2a5..51a320f 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenController.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenController.java @@ -1,14 +1,18 @@ package it.gov.pagopa.onboarding.citizen.controller; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; +import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentStateUpdateDTO; import jakarta.validation.Valid; +import jakarta.validation.constraints.Pattern; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; import java.util.List; +import static it.gov.pagopa.onboarding.citizen.constants.CitizenConstants.ValidationRegex.FISCAL_CODE_STRUCTURE_REGEX; + @RequestMapping("/emd/citizen") public interface CitizenController { @@ -16,15 +20,6 @@ public interface CitizenController { @PostMapping("") Mono> saveCitizenConsent(@Valid @RequestBody CitizenConsentDTO citizenConsentDTO); - /** - * Update the state of a citizen's consent. - * - * @param citizenConsentDTO contains the hashedFiscalCode, channelId, and channelState to update - * @return the updated citizen consents - */ - @PutMapping("/stateUpdate") - Mono> stateUpdate(@Valid @RequestBody CitizenConsentDTO citizenConsentDTO); - /** * Get the consent status for a specific citizen and channel. * @@ -33,7 +28,16 @@ public interface CitizenController { * @return the citizen consent status */ @GetMapping("/{fiscalCode}/{tppId}") - Mono> getConsentStatus(@PathVariable String fiscalCode, @PathVariable String tppId); + Mono> getConsentStatus(@PathVariable @Pattern(regexp = FISCAL_CODE_STRUCTURE_REGEX, message = "Invalid fiscal code format") String fiscalCode, @PathVariable String tppId); + + /** + * Update the state of a citizen's consent. + * + * @param citizenConsentStateUpdateDTO contains the hashedFiscalCode, channelId, and channelState to update + * @return the updated citizen consents + */ + @PutMapping("/stateUpdate") + Mono> stateUpdate(@Valid @RequestBody CitizenConsentStateUpdateDTO citizenConsentStateUpdateDTO); /** * List all channels with enabled consents for a specific citizen. @@ -42,7 +46,7 @@ public interface CitizenController { * @return a list of channels with enabled consents */ @GetMapping("/list/{fiscalCode}/enabled") - Mono>> getCitizenConsentsEnabled(@PathVariable String fiscalCode); + Mono>> getCitizenConsentsEnabled(@PathVariable @Pattern(regexp = FISCAL_CODE_STRUCTURE_REGEX, message = "Invalid fiscal code format") String fiscalCode); /** * List all channels and their consent status for a specific citizen. @@ -51,6 +55,6 @@ public interface CitizenController { * @return a list of all channels with their consent statuses */ @GetMapping("/list/{fiscalCode}") - Mono>> getCitizenConsents(@PathVariable String fiscalCode); + Mono>> getCitizenConsents(@PathVariable @Pattern(regexp = FISCAL_CODE_STRUCTURE_REGEX, message = "Invalid fiscal code format") String fiscalCode); } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java b/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java index 668325d..85b5156 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java @@ -1,6 +1,7 @@ package it.gov.pagopa.onboarding.citizen.controller; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; +import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentStateUpdateDTO; import it.gov.pagopa.onboarding.citizen.service.CitizenServiceImpl; import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; @@ -25,11 +26,11 @@ public Mono> saveCitizenConsent(@Valid Citizen } @Override - public Mono> stateUpdate(@Valid CitizenConsentDTO citizenConsentDTO) { + public Mono> stateUpdate(@Valid CitizenConsentStateUpdateDTO citizenConsentStateUpdateDTO) { return citizenService.updateChannelState( - citizenConsentDTO.getHashedFiscalCode(), //at this stage the fiscalCode has not yet been hashed - citizenConsentDTO.getTppId(), - citizenConsentDTO.getTppState()) + citizenConsentStateUpdateDTO.getHashedFiscalCode(), + citizenConsentStateUpdateDTO.getTppId(), + citizenConsentStateUpdateDTO.getTppState()) .map(ResponseEntity::ok); } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java index c35fec5..931a4e3 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java @@ -7,6 +7,7 @@ import lombok.experimental.SuperBuilder; import java.time.LocalDateTime; +import java.util.Map; @Data @SuperBuilder @@ -15,8 +16,16 @@ public class CitizenConsentDTO { @JsonAlias("fiscalCode") private String hashedFiscalCode; - private String tppId; - private Boolean tppState; - private LocalDateTime creationDate; - private LocalDateTime lastUpdateDate; + private Map consents; + + @Data + @SuperBuilder + @NoArgsConstructor + @AllArgsConstructor + public static class ConsentDTO { + private Boolean tc; + private Boolean tppState; + private LocalDateTime creationDate; + private LocalDateTime lastUpdateDate; + } } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentStateUpdateDTO.java b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentStateUpdateDTO.java new file mode 100644 index 0000000..973eb2a --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentStateUpdateDTO.java @@ -0,0 +1,16 @@ +package it.gov.pagopa.onboarding.citizen.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.AllArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +public class CitizenConsentStateUpdateDTO { + private String hashedFiscalCode; + private String tppId; + private Boolean tppState; +} diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/Contact.java b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/Contact.java new file mode 100644 index 0000000..fa6c88d --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/Contact.java @@ -0,0 +1,15 @@ +package it.gov.pagopa.onboarding.citizen.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class Contact { + + private String name; + private String number; + private String email; +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/TppDTO.java b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/TppDTO.java new file mode 100644 index 0000000..bc22e8b --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/TppDTO.java @@ -0,0 +1,26 @@ +package it.gov.pagopa.onboarding.citizen.dto; + + +import it.gov.pagopa.onboarding.citizen.enums.AuthenticationType; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@SuperBuilder +@NoArgsConstructor +public class TppDTO { + @NotNull + private String tppId; + private String entityId; + private String businessName; + private String messageUrl; + private String authenticationUrl; + private AuthenticationType authenticationType; + private Contact contact; + private Boolean state; + + + +} diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentObjectToDTOMapper.java b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentObjectToDTOMapper.java index 022d91d..f663d34 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentObjectToDTOMapper.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentObjectToDTOMapper.java @@ -1,20 +1,29 @@ package it.gov.pagopa.onboarding.citizen.dto.mapper; - import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; +import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO.ConsentDTO; import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; import org.springframework.stereotype.Service; +import java.util.HashMap; +import java.util.Map; + @Service public class CitizenConsentObjectToDTOMapper { - public CitizenConsentDTO map(CitizenConsent citizenConsent){ + public CitizenConsentDTO map(CitizenConsent citizenConsent) { + Map consentsDTO = new HashMap<>(); + + citizenConsent.getConsents().forEach((tppId, consentDetails) -> consentsDTO.put(tppId, ConsentDTO.builder() + .tc(consentDetails.getTc()) + .tppState(consentDetails.getTppState()) + .creationDate(consentDetails.getCreationDate()) + .lastUpdateDate(consentDetails.getLastUpdateDate()) + .build())); + return CitizenConsentDTO.builder() .hashedFiscalCode(citizenConsent.getHashedFiscalCode()) - .tppState(citizenConsent.getTppState()) - .tppId(citizenConsent.getTppId()) - .creationDate(citizenConsent.getCreationDate()) - .lastUpdateDate(citizenConsent.getLastUpdateDate()) + .consents(consentsDTO) .build(); } } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/enums/AuthenticationType.java b/src/main/java/it/gov/pagopa/onboarding/citizen/enums/AuthenticationType.java new file mode 100644 index 0000000..26c74ce --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/enums/AuthenticationType.java @@ -0,0 +1,16 @@ +package it.gov.pagopa.onboarding.citizen.enums; + +import lombok.Getter; + +@Getter +public enum AuthenticationType { + OAUTH2("OAUTH2"); + + + private final String status; + + AuthenticationType(String status) { + this.status = status; + } + +} diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java b/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java index 64ebd8e..5b37004 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java @@ -5,7 +5,7 @@ import lombok.experimental.SuperBuilder; import org.springframework.data.mongodb.core.mapping.Document; -import java.time.LocalDateTime; +import java.util.Map; @Document(collection = "citizen_consents") @Data @@ -15,9 +15,7 @@ public class CitizenConsent { private String id; private String hashedFiscalCode; - private String tppId; - private Boolean tppState; - private LocalDateTime creationDate; - private LocalDateTime lastUpdateDate; + private Map consents; } + diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/model/ConsentDetails.java b/src/main/java/it/gov/pagopa/onboarding/citizen/model/ConsentDetails.java new file mode 100644 index 0000000..27aacf0 --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/model/ConsentDetails.java @@ -0,0 +1,18 @@ +package it.gov.pagopa.onboarding.citizen.model; + +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@SuperBuilder +public class ConsentDetails { + private Boolean tc; + private Boolean tppState; + private LocalDateTime creationDate; + private LocalDateTime lastTcUpdateDate; + private LocalDateTime lastUpdateDate; +} diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentDTOToObjectMapper.java b/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentDTOToObjectMapper.java index 96caf6a..4c3aef2 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentDTOToObjectMapper.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentDTOToObjectMapper.java @@ -1,18 +1,29 @@ package it.gov.pagopa.onboarding.citizen.model.mapper; - import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; +import it.gov.pagopa.onboarding.citizen.model.ConsentDetails; import org.springframework.stereotype.Service; +import java.util.HashMap; +import java.util.Map; + @Service public class CitizenConsentDTOToObjectMapper { - public CitizenConsent map(CitizenConsentDTO citizenConsentDTO){ + public CitizenConsent map(CitizenConsentDTO citizenConsentDTO) { + Map consents = new HashMap<>(); + + citizenConsentDTO.getConsents().forEach((tppId, consentDTO) -> consents.put(tppId, ConsentDetails.builder() + .tc(consentDTO.getTc()) + .tppState(consentDTO.getTppState()) + .creationDate(consentDTO.getCreationDate()) + .lastTcUpdateDate(consentDTO.getLastUpdateDate()) + .build())); + return CitizenConsent.builder() - .tppState(true) - .tppId(citizenConsentDTO.getTppId()) .hashedFiscalCode(citizenConsentDTO.getHashedFiscalCode()) + .consents(consents) .build(); } } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenRepository.java b/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenRepository.java index 103dc2f..fb58a14 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenRepository.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenRepository.java @@ -3,14 +3,13 @@ import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -public interface CitizenRepository extends ReactiveMongoRepository { +public interface CitizenRepository extends ReactiveMongoRepository, CitizenSpecificRepository { Flux findByHashedFiscalCode(String hashedFiscalCode); - Flux findByHashedFiscalCodeAndTppStateTrue(String hashedFiscalCode); + //Flux findByHashedFiscalCodeAndTppStateTrue(String hashedFiscalCode); - Mono findByHashedFiscalCodeAndTppId(String hashedFiscalCode, String tppId); + //Mono findByHashedFiscalCodeAndTppId(String hashedFiscalCode, String tppId); } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepository.java b/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepository.java new file mode 100644 index 0000000..43932e7 --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepository.java @@ -0,0 +1,10 @@ +package it.gov.pagopa.onboarding.citizen.repository; + +import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public interface CitizenSpecificRepository { + Flux findByHashedFiscalCodeAndTppStateTrue(String hashedFiscalCode); + Mono findByHashedFiscalCodeAndTppId(String hashedFiscalCode, String tppId); +} diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepositoryImpl.java b/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepositoryImpl.java new file mode 100644 index 0000000..81db2b4 --- /dev/null +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepositoryImpl.java @@ -0,0 +1,61 @@ +package it.gov.pagopa.onboarding.citizen.repository; + +import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; +import it.gov.pagopa.onboarding.citizen.model.ConsentDetails; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.data.mongodb.core.aggregation.Aggregation; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.stereotype.Repository; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.Map; +import java.util.stream.Collectors; + +@Repository +public class CitizenSpecificRepositoryImpl implements CitizenSpecificRepository { + + private final ReactiveMongoTemplate mongoTemplate; + + public CitizenSpecificRepositoryImpl(ReactiveMongoTemplate mongoTemplate) { + this.mongoTemplate = mongoTemplate; + } + + public Flux findByHashedFiscalCodeAndTppStateTrue(String hashedFiscalCode) { + Aggregation aggregation = Aggregation.newAggregation( + Aggregation.match(Criteria.where("hashedFiscalCode").is(hashedFiscalCode)), + Aggregation.unwind("consents"), + Aggregation.match(Criteria.where("consents.tppState").is(true)) + ); + + return mongoTemplate.aggregate(aggregation, CitizenConsent.class, CitizenConsent.class) + .flatMap(result -> { + Map validConsents = result.getConsents() + .entrySet() + .stream() + .filter(entry -> entry.getValue().getTppState()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + + return Flux.just(CitizenConsent.builder() + .id(result.getId()) + .hashedFiscalCode(result.getHashedFiscalCode()) + .consents(validConsents) + .build()); + }); + } + + public Mono findByHashedFiscalCodeAndTppId(String hashedFiscalCode, String tppId) { + if (tppId == null) { + return Mono.empty(); + } + + Aggregation aggregation = Aggregation.newAggregation( + Aggregation.match(Criteria.where("hashedFiscalCode").is(hashedFiscalCode)), + Aggregation.match(Criteria.where("consents." + tppId).exists(true)) + ); + + return mongoTemplate.aggregate(aggregation, CitizenConsent.class, CitizenConsent.class) + .next(); + } + +} diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java b/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java index ddcc279..16fbafa 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java @@ -2,10 +2,12 @@ import it.gov.pagopa.common.utils.Utils; import it.gov.pagopa.onboarding.citizen.configuration.ExceptionMap; +import it.gov.pagopa.onboarding.citizen.connector.tpp.TppConnectorImpl; import it.gov.pagopa.onboarding.citizen.constants.CitizenConstants.ExceptionName; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; import it.gov.pagopa.onboarding.citizen.dto.mapper.CitizenConsentObjectToDTOMapper; import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; +import it.gov.pagopa.onboarding.citizen.model.ConsentDetails; import it.gov.pagopa.onboarding.citizen.model.mapper.CitizenConsentDTOToObjectMapper; import it.gov.pagopa.onboarding.citizen.repository.CitizenRepository; import lombok.extern.slf4j.Slf4j; @@ -25,30 +27,49 @@ public class CitizenServiceImpl implements CitizenService { private final CitizenConsentObjectToDTOMapper mapperToDTO; private final CitizenConsentDTOToObjectMapper mapperToObject; private final ExceptionMap exceptionMap; + private final TppConnectorImpl tppConnector; - public CitizenServiceImpl(CitizenRepository citizenRepository, CitizenConsentObjectToDTOMapper mapperToDTO, CitizenConsentDTOToObjectMapper mapperToObject, ExceptionMap exceptionMap) { + public CitizenServiceImpl(CitizenRepository citizenRepository, CitizenConsentObjectToDTOMapper mapperToDTO, CitizenConsentDTOToObjectMapper mapperToObject, ExceptionMap exceptionMap, TppConnectorImpl tppConnector) { this.citizenRepository = citizenRepository; this.mapperToDTO = mapperToDTO; this.mapperToObject = mapperToObject; this.exceptionMap = exceptionMap; + this.tppConnector = tppConnector; } + @Override public Mono createCitizenConsent(CitizenConsentDTO citizenConsentDTO) { CitizenConsent citizenConsent = mapperToObject.map(citizenConsentDTO); String hashedFiscalCode = Utils.createSHA256(citizenConsent.getHashedFiscalCode()); citizenConsent.setHashedFiscalCode(hashedFiscalCode); - citizenConsent.setCreationDate(LocalDateTime.now()); - citizenConsent.setLastUpdateDate(LocalDateTime.now()); - log.info("[EMD-CITIZEN][CREATE] Received consent: {}",inputSanify(citizenConsent.toString())); - return citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode,citizenConsent.getTppId()) + + citizenConsent.getConsents().forEach((tppId, consentDetails) -> { + consentDetails.setCreationDate(LocalDateTime.now()); + consentDetails.setLastUpdateDate(LocalDateTime.now()); + }); + + log.info("[EMD-CITIZEN][CREATE] Received consent: {}", inputSanify(citizenConsent.toString())); + + String tppId = citizenConsent.getConsents().keySet().stream().findFirst().orElse(null); + if (tppId == null) { + return Mono.error(exceptionMap.throwException(ExceptionName.TPP_NOT_FOUND, "TPP does not exist or is not active")); + } + + return citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId) .flatMap(existingConsent -> { log.info("[EMD][CREATE-CITIZEN-CONSENT] Citizen consent already exists"); return Mono.just(mapperToDTO.map(existingConsent)); }) - .switchIfEmpty( - citizenRepository.save(citizenConsent) - .doOnSuccess(savedConsent -> log.info("[EMD][CREATE-CITIZEN-CONSENT] Created new citizen consent")) - .flatMap(savedConsent -> Mono.just(mapperToDTO.map(savedConsent))) + .switchIfEmpty(tppConnector.get(tppId) + .flatMap(tppResponse -> { + if (tppResponse != null && Boolean.TRUE.equals(tppResponse.getState())) { + return citizenRepository.save(citizenConsent) + .doOnSuccess(savedConsent -> log.info("[EMD][CREATE-CITIZEN-CONSENT] Created new citizen consent")) + .flatMap(savedConsent -> Mono.just(mapperToDTO.map(savedConsent))); + } else { + return Mono.error(exceptionMap.throwException(ExceptionName.TPP_NOT_FOUND, "TPP does not exist or is not active")); + } + }) ); } @@ -56,13 +77,19 @@ public Mono createCitizenConsent(CitizenConsentDTO citizenCon public Mono updateChannelState(String fiscalCode, String tppId, boolean tppState) { String hashedFiscalCode = Utils.createSHA256(fiscalCode); log.info("[EMD][[CITIZEN][UPDATE-CHANNEL-STATE] Received hashedFiscalCode: {} and tppId: {} with state: {}" - ,hashedFiscalCode, inputSanify(tppId), tppState); + , hashedFiscalCode, inputSanify(tppId), tppState); return citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId) .switchIfEmpty(Mono.error(exceptionMap.throwException - (ExceptionName.CITIZEN_NOT_ONBOARDED,"Citizen consent not founded during update state process"))) + (ExceptionName.CITIZEN_NOT_ONBOARDED, "Citizen consent not founded during update state process"))) .flatMap(citizenConsent -> { - citizenConsent.setTppState(tppState); - citizenConsent.setLastUpdateDate(LocalDateTime.now()); + ConsentDetails consentDetails = citizenConsent.getConsents().get(tppId); + if (consentDetails != null) { + consentDetails.setTppState(tppState); + consentDetails.setLastUpdateDate(LocalDateTime.now()); + } else { + return Mono.error(exceptionMap.throwException + (ExceptionName.CITIZEN_NOT_ONBOARDED, "ConsentDetails is null for this tppId")); + } return citizenRepository.save(citizenConsent); }) .map(mapperToDTO::map) @@ -72,39 +99,39 @@ public Mono updateChannelState(String fiscalCode, String tppI @Override public Mono getConsentStatus(String fiscalCode, String tppId) { String hashedFiscalCode = Utils.createSHA256(fiscalCode); - log.info("[EMD-CITIZEN][GET-CONSENT-STATUS] Received hashedFiscalCode: {} and tppId: {}",hashedFiscalCode,inputSanify(tppId)); + log.info("[EMD-CITIZEN][GET-CONSENT-STATUS] Received hashedFiscalCode: {} and tppId: {}", hashedFiscalCode, inputSanify(tppId)); return citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId) .switchIfEmpty(Mono.error(exceptionMap.throwException - (ExceptionName.CITIZEN_NOT_ONBOARDED,"Citizen consent not founded during get process "))) + (ExceptionName.CITIZEN_NOT_ONBOARDED, "Citizen consent not founded during get process "))) .map(mapperToDTO::map) - .doOnSuccess(consent -> log.info("[EMD-CITIZEN][GET-CONSENT-STATUS] Consent consent found:: {}",consent)); + .doOnSuccess(consent -> log.info("[EMD-CITIZEN][GET-CONSENT-STATUS] Consent consent found:: {}", consent)); } @Override public Mono> getListEnabledConsents(String fiscalCode) { String hashedFiscalCode = Utils.createSHA256(fiscalCode); - log.info("[EMD-CITIZEN][FIND-CITIZEN-CONSENTS-ENABLED] Received hashedFiscalCode: {}",hashedFiscalCode); + log.info("[EMD-CITIZEN][FIND-CITIZEN-CONSENTS-ENABLED] Received hashedFiscalCode: {}", hashedFiscalCode); return citizenRepository.findByHashedFiscalCodeAndTppStateTrue(hashedFiscalCode) .collectList() .map(consentList -> consentList.stream() .map(mapperToDTO::map) .toList() ) - .doOnSuccess(consentList -> log.info("EMD][CITIZEN][FIND-CITIZEN-CONSENTS-ENABLED] Consents founded: {}",(consentList.size()))); + .doOnSuccess(consentList -> log.info("EMD][CITIZEN][FIND-CITIZEN-CONSENTS-ENABLED] Consents founded: {}", (consentList.size()))); } @Override public Mono> getListAllConsents(String fiscalCode) { String hashedFiscalCode = Utils.createSHA256(fiscalCode); - log.info("[EMD-CITIZEN][FIND-ALL-CITIZEN-CONSENTS] Received hashedFiscalCode: {}",(hashedFiscalCode)); + log.info("[EMD-CITIZEN][FIND-ALL-CITIZEN-CONSENTS] Received hashedFiscalCode: {}", (hashedFiscalCode)); return citizenRepository.findByHashedFiscalCode(hashedFiscalCode) .collectList() .map(consentList -> consentList.stream() .map(mapperToDTO::map) .toList() ) - .doOnSuccess(consentList -> log.info("[EMD-CITIZEN][FIND-ALL-CITIZEN-CONSENTS] Consents found:: {}",consentList)); + .doOnSuccess(consentList -> log.info("[EMD-CITIZEN][FIND-ALL-CITIZEN-CONSENTS] Consents found:: {}", consentList)); } } diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java b/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java index f49c259..d955423 100644 --- a/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java @@ -1,7 +1,9 @@ package it.gov.pagopa.onboarding.citizen.controller; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; +import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentStateUpdateDTO; import it.gov.pagopa.onboarding.citizen.faker.CitizenConsentDTOFaker; +import it.gov.pagopa.onboarding.citizen.faker.CitizenConsentStateUpdateDTOFaker; import it.gov.pagopa.onboarding.citizen.service.CitizenServiceImpl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -26,7 +28,7 @@ class CitizenControllerTest { - private static final String FISCAL_CODE = "fiscalCode"; + private static final String FISCAL_CODE = "MLXHZZ43A70H203T"; private static final String TPP_ID = "tppId"; @@ -52,25 +54,27 @@ void saveCitizenConsent_Ok() { @Test void stateUpdate_Ok() { - CitizenConsentDTO citizenConsentDTO = CitizenConsentDTOFaker.mockInstance(true); + CitizenConsentStateUpdateDTO citizenConsentStateUpdateDTO = CitizenConsentStateUpdateDTOFaker.mockInstance(true); + + CitizenConsentDTO expectedResponseDTO = CitizenConsentDTOFaker.mockInstance(true); Mockito.when(citizenService.updateChannelState( - citizenConsentDTO.getHashedFiscalCode(), - citizenConsentDTO.getTppId(), - citizenConsentDTO.getTppState())) - .thenReturn(Mono.just(citizenConsentDTO)); + citizenConsentStateUpdateDTO.getHashedFiscalCode(), + citizenConsentStateUpdateDTO.getTppId(), + citizenConsentStateUpdateDTO.getTppState())) + .thenReturn(Mono.just(expectedResponseDTO)); webClient.put() .uri("/emd/citizen/stateUpdate") .contentType(MediaType.APPLICATION_JSON) - .bodyValue(citizenConsentDTO) + .bodyValue(citizenConsentStateUpdateDTO) .exchange() .expectStatus().isOk() .expectBody(CitizenConsentDTO.class) .consumeWith(response -> { CitizenConsentDTO resultResponse = response.getResponseBody(); Assertions.assertNotNull(resultResponse); - Assertions.assertEquals(citizenConsentDTO, resultResponse); + Assertions.assertEquals(expectedResponseDTO, resultResponse); }); } diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentDTOFaker.java b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentDTOFaker.java index 2c639cc..a135012 100644 --- a/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentDTOFaker.java +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentDTOFaker.java @@ -1,21 +1,22 @@ package it.gov.pagopa.onboarding.citizen.faker; - import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; - import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; public class CitizenConsentDTOFaker { - private CitizenConsentDTOFaker(){} + private CitizenConsentDTOFaker() {} + public static CitizenConsentDTO mockInstance(Boolean bias) { + Map consents = new HashMap<>(); + + consents.put("tppId", new CitizenConsentDTO.ConsentDTO(bias, bias, LocalDateTime.now(), LocalDateTime.now())); + return CitizenConsentDTO.builder() - .tppId("tppId") - .tppState(bias) .hashedFiscalCode("hashedFiscalCode") - .creationDate(LocalDateTime.now()) - .lastUpdateDate(LocalDateTime.now()) + .consents(consents) .build(); - } } diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentFaker.java b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentFaker.java index 195afad..fec5c44 100644 --- a/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentFaker.java +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentFaker.java @@ -1,20 +1,32 @@ package it.gov.pagopa.onboarding.citizen.faker; - import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; +import it.gov.pagopa.onboarding.citizen.model.ConsentDetails; import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; public class CitizenConsentFaker { - private CitizenConsentFaker(){} + private CitizenConsentFaker() {} + public static CitizenConsent mockInstance(Boolean bias) { - return CitizenConsent.builder() - .tppId("tppId") + Map consents = new HashMap<>(); + + ConsentDetails consentDetails = ConsentDetails.builder() + .tc(bias) .tppState(bias) - .hashedFiscalCode("hashedFiscalCode") .creationDate(LocalDateTime.now()) + .lastTcUpdateDate(LocalDateTime.now()) .lastUpdateDate(LocalDateTime.now()) .build(); + + consents.put("tppId", consentDetails); + + return CitizenConsent.builder() + .hashedFiscalCode("hashedFiscalCode") + .consents(consents) + .build(); } } diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentStateUpdateDTOFaker.java b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentStateUpdateDTOFaker.java new file mode 100644 index 0000000..6685dcb --- /dev/null +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/CitizenConsentStateUpdateDTOFaker.java @@ -0,0 +1,16 @@ +package it.gov.pagopa.onboarding.citizen.faker; + +import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentStateUpdateDTO; + +public class CitizenConsentStateUpdateDTOFaker { + + private CitizenConsentStateUpdateDTOFaker() {} + + public static CitizenConsentStateUpdateDTO mockInstance(Boolean tppState) { + return CitizenConsentStateUpdateDTO.builder() + .hashedFiscalCode("hashedFiscalCode") + .tppId("tppId") + .tppState(tppState) + .build(); + } +} diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/faker/TppDTOFaker.java b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/TppDTOFaker.java new file mode 100644 index 0000000..b5befd4 --- /dev/null +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/faker/TppDTOFaker.java @@ -0,0 +1,12 @@ +package it.gov.pagopa.onboarding.citizen.faker; + +import it.gov.pagopa.onboarding.citizen.dto.TppDTO; + +public class TppDTOFaker { + private TppDTOFaker(){} + public static TppDTO mockInstance() { + return TppDTO.builder() + .tppId("id") + .build(); + } +} diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepositoryImplTest.java b/src/test/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepositoryImplTest.java new file mode 100644 index 0000000..f3ca0cd --- /dev/null +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/repository/CitizenSpecificRepositoryImplTest.java @@ -0,0 +1,78 @@ +package it.gov.pagopa.onboarding.citizen.repository; + +import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; +import it.gov.pagopa.onboarding.citizen.model.ConsentDetails; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class CitizenSpecificRepositoryImplTest { + + private ReactiveMongoTemplate mongoTemplate; + private CitizenSpecificRepositoryImpl repository; + + @BeforeEach + public void setUp() { + mongoTemplate = Mockito.mock(ReactiveMongoTemplate.class); + repository = new CitizenSpecificRepositoryImpl(mongoTemplate); + } + + @Test + void testFindByHashedFiscalCodeAndTppStateTrue() { + String hashedFiscalCode = "hashedCode"; + CitizenConsent citizenConsent = new CitizenConsent(); + citizenConsent.setId("1"); + citizenConsent.setHashedFiscalCode(hashedFiscalCode); + + Map consents = new HashMap<>(); + ConsentDetails consentDetails = new ConsentDetails(); + consentDetails.setTppState(true); + consents.put("tpp1", consentDetails); + citizenConsent.setConsents(consents); + + when(mongoTemplate.aggregate(Mockito.any(), Mockito.eq(CitizenConsent.class), Mockito.eq(CitizenConsent.class))) + .thenReturn(Flux.just(citizenConsent)); + + Flux result = repository.findByHashedFiscalCodeAndTppStateTrue(hashedFiscalCode); + + Assertions.assertEquals(1, result.count().block()); + Assertions.assertEquals(hashedFiscalCode, result.blockFirst().getHashedFiscalCode()); + Mockito.verify(mongoTemplate).aggregate(Mockito.any(), Mockito.eq(CitizenConsent.class), Mockito.eq(CitizenConsent.class)); + } + + @Test + void testFindByHashedFiscalCodeAndTppId() { + String hashedFiscalCode = "hashedCode"; + String tppId = "tpp1"; + CitizenConsent citizenConsent = new CitizenConsent(); + citizenConsent.setId("1"); + citizenConsent.setHashedFiscalCode(hashedFiscalCode); + + Map consents = new HashMap<>(); + ConsentDetails consentDetails = new ConsentDetails(); + consentDetails.setTppState(true); + consents.put(tppId, consentDetails); + citizenConsent.setConsents(consents); + + when(mongoTemplate.aggregate(Mockito.any(), Mockito.eq(CitizenConsent.class), Mockito.eq(CitizenConsent.class))) + .thenReturn(Flux.just(citizenConsent)); + + Mono result = repository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId); + + Assertions.assertEquals(hashedFiscalCode, result.block().getHashedFiscalCode()); + Mockito.verify(mongoTemplate).aggregate(Mockito.any(), Mockito.eq(CitizenConsent.class), Mockito.eq(CitizenConsent.class)); + } + +} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java b/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java index 5f3b54e..0f6cf85 100644 --- a/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java @@ -2,12 +2,15 @@ import it.gov.pagopa.common.utils.Utils; import it.gov.pagopa.common.web.exception.ClientExceptionWithBody; -import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; -import it.gov.pagopa.onboarding.citizen.dto.mapper.CitizenConsentObjectToDTOMapper; import it.gov.pagopa.common.web.exception.EmdEncryptionException; import it.gov.pagopa.onboarding.citizen.configuration.ExceptionMap; +import it.gov.pagopa.onboarding.citizen.connector.tpp.TppConnectorImpl; +import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; +import it.gov.pagopa.onboarding.citizen.dto.TppDTO; +import it.gov.pagopa.onboarding.citizen.dto.mapper.CitizenConsentObjectToDTOMapper; import it.gov.pagopa.onboarding.citizen.faker.CitizenConsentDTOFaker; import it.gov.pagopa.onboarding.citizen.faker.CitizenConsentFaker; +import it.gov.pagopa.onboarding.citizen.faker.TppDTOFaker; import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; import it.gov.pagopa.onboarding.citizen.model.mapper.CitizenConsentDTOToObjectMapper; import it.gov.pagopa.onboarding.citizen.repository.CitizenRepository; @@ -45,6 +48,9 @@ class CitizenServiceTest { @MockBean CitizenRepository citizenRepository; + @MockBean + TppConnectorImpl tppConnector; + @Autowired CitizenConsentObjectToDTOMapper dtoMapper; @@ -54,40 +60,91 @@ class CitizenServiceTest { private static final boolean TPP_STATE = true; private static final CitizenConsent CITIZEN_CONSENT = CitizenConsentFaker.mockInstance(true); private static final CitizenConsentDTO CITIZEN_CONSENT_DTO = CitizenConsentDTOFaker.mockInstance(true); + @Test void createCitizenConsent_Ok() { - CitizenConsentDTO citizenConsentDTO = dtoMapper.map(CITIZEN_CONSENT); + TppDTO mockTppDTO = new TppDTO(); + mockTppDTO.setTppId(CITIZEN_CONSENT_DTO.getConsents().keySet().stream().findFirst().orElse(null)); + mockTppDTO.setState(true); + + Mockito.when(tppConnector.get(anyString())) + .thenReturn(Mono.just(mockTppDTO)); + Mockito.when(citizenRepository.save(Mockito.any())) .thenReturn(Mono.just(CITIZEN_CONSENT)); Mockito.when(citizenRepository.findById(anyString())) .thenReturn(Mono.empty()); + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(anyString(), anyString())) + .thenReturn(Mono.empty()); + CitizenConsentDTO response = citizenService.createCitizenConsent(CITIZEN_CONSENT_DTO).block(); assertNotNull(response); - assertEquals(citizenConsentDTO, response); } @Test void createCitizenConsent_AlreadyExists() { - CitizenConsentDTO citizenConsentDTO = dtoMapper.map(CITIZEN_CONSENT); + TppDTO mockTppDTO = TppDTOFaker.mockInstance(); + mockTppDTO.setState(true); + + Mockito.when(tppConnector.get(anyString())) + .thenReturn(Mono.just(mockTppDTO)); + Mockito.when(citizenRepository.save(Mockito.any())) .thenReturn(Mono.empty()); Mockito.when(citizenRepository.findById(anyString())) .thenReturn(Mono.just(CITIZEN_CONSENT)); + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(anyString(), anyString())) + .thenReturn(Mono.just(CITIZEN_CONSENT)); + CitizenConsentDTO response = citizenService.createCitizenConsent(CITIZEN_CONSENT_DTO).block(); assertNotNull(response); - assertEquals(citizenConsentDTO, response); } + @Test + void createCitizenConsent_Ko_TppNull() { + + CitizenConsentDTO citizenConsentDTO = CitizenConsentDTOFaker.mockInstance(true); + citizenConsentDTO.getConsents().clear(); + + Mockito.when(tppConnector.get(anyString())).thenReturn(Mono.empty()); + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(anyString(), anyString())) + .thenReturn(Mono.empty()); + + ClientExceptionWithBody exception = assertThrows(ClientExceptionWithBody.class, + () -> citizenService.createCitizenConsent(citizenConsentDTO).block()); + + assertEquals("TPP does not exist or is not active", exception.getMessage()); + } + + @Test + void createCitizenConsent_Ko_TppInactive() { + + TppDTO mockTppDTO = TppDTOFaker.mockInstance(); + mockTppDTO.setState(false); + + Mockito.when(tppConnector.get(anyString())).thenReturn(Mono.just(mockTppDTO)); + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(anyString(), anyString())) + .thenReturn(Mono.empty()); + + CitizenConsentDTO citizenConsentDTO = dtoMapper.map(CITIZEN_CONSENT); + + ClientExceptionWithBody exception = assertThrows(ClientExceptionWithBody.class, + () -> citizenService.createCitizenConsent(citizenConsentDTO).block()); + + assertEquals("TPP does not exist or is not active", exception.getMessage()); + Mockito.verify(citizenRepository, Mockito.never()).save(Mockito.any()); + } + @Test void createCitizenConsent_Ko_EmdEncryptError() { CitizenConsentDTO citizenConsentDTO = CitizenConsentDTOFaker.mockInstance(true); @@ -106,12 +163,15 @@ void updateChannelState_Ok() { Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(HASHED_FISCAL_CODE, TPP_ID)) .thenReturn(Mono.just(CITIZEN_CONSENT)); + Mockito.when(citizenRepository.save(Mockito.any())) .thenReturn(Mono.just(CITIZEN_CONSENT)); CitizenConsentDTO response = citizenService.updateChannelState(FISCAL_CODE, TPP_ID, TPP_STATE).block(); + assertNotNull(response); - assertEquals(TPP_STATE, response.getTppState()); + + assertEquals(TPP_STATE, response.getConsents().get(TPP_ID).getTppState()); } @Test @@ -127,6 +187,24 @@ void updateChannelState_Ko_CitizenNotOnboarded() { assertEquals("Citizen consent not founded during update state process", exception.getMessage()); } + @Test + void updateChannelState_Ok_ConsentDetailsIsNull() { + CitizenConsent citizenConsentWithConsentDetailNull = CitizenConsentFaker.mockInstance(true); + citizenConsentWithConsentDetailNull.getConsents().put(TPP_ID, null); + + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(HASHED_FISCAL_CODE, TPP_ID)) + .thenReturn(Mono.just(citizenConsentWithConsentDetailNull)); + + Mockito.when(citizenRepository.save(Mockito.any())) + .thenReturn(Mono.just(citizenConsentWithConsentDetailNull)); + + Executable executable = () -> citizenService.updateChannelState(FISCAL_CODE, TPP_ID, TPP_STATE).block(); + ClientExceptionWithBody exception = assertThrows(ClientExceptionWithBody.class, executable); + + assertEquals("ConsentDetails is null for this tppId", exception.getMessage()); + } + + @Test void getConsentStatus_Ok() {