Skip to content

Commit

Permalink
feat(vaccination info): Apps connected to EPS can submit a vaccinatio…
Browse files Browse the repository at this point in the history
…n information lists via the JSON-RPC method `submitVaccinationInfoList`. The information is saved and made available to health department staff via the front end.

Refs iris-connect/iris-backlog#274
  • Loading branch information
jekutzsche committed Mar 2, 2022
1 parent 412e145 commit 6fa4277
Show file tree
Hide file tree
Showing 33 changed files with 1,188 additions and 44 deletions.
5 changes: 5 additions & 0 deletions iris-client-bff/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.googlecode.libphonenumber</groupId>
<artifactId>libphonenumber</artifactId>
<version>8.12.44</version>
</dependency>

<!-- Security -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
package iris.client_bff.cases;

import io.vavr.control.Try;
import iris.client_bff.core.EmailAddress;
import iris.client_bff.core.mail.EmailProvider;
import iris.client_bff.core.mail.EmailSender;
import iris.client_bff.core.mail.EmailSender.TemplatedEmail.ConfiguredRecipient;
import iris.client_bff.core.model.EmailAddress;
import iris.client_bff.core.mail.EmailTemplates;
import lombok.AccessLevel;
import lombok.Setter;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public CompositeJsonServiceExporter jsonRpcServiceImplExporterWithSlash() {
private CompositeJsonServiceExporter createCompositeJsonServiceExporter() {

CompositeJsonServiceExporter compositeJsonServiceExporter = new CompositeJsonServiceExporter();
compositeJsonServiceExporter.setServiceInterfaces(new Class[] { CaseDataController.class, EventDataController.class,
IrisMessageDataController.class, VaccinationInfoController.class });
compositeJsonServiceExporter.setServices(new Object[] { caseDataController, eventDataController,
irisMessageDataController, vaccinationProofController });
compositeJsonServiceExporter.setAllowExtraParams(true); // Used to allow the EPS to add common parameters (e.g. a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,50 @@

import iris.client_bff.ui.messages.ErrorMessages;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;

import java.util.Arrays;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;

@Configuration
@RequiredArgsConstructor
public class JsonRpcDataValidator {

private final Validator validator;
private final Validator validator;

public void validateData(Object... data) {

Arrays.stream(data)
.map(validator::validate)
.flatMap(Set::stream)
.map(this::createViolationPair)
.reduce(this::joinViolations)
.ifPresent(this::throwException);
}

public void validateData(Object data) {

validator.validate(data).stream()
.map(this::createViolationPair)
.reduce(this::joinViolations)
.ifPresent(this::throwException);
}

private String createViolationPair(ConstraintViolation<Object> violation) {
return String.format("%s: %s", violation.getPropertyPath(), violation.getMessage());
}

public void validateData(Object data) {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(data);
if (!constraintViolations.isEmpty())
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
ErrorMessages.INVALID_INPUT + ": " + constraintViolations.stream().map(violation -> String.format("%s: %s", violation.getPropertyPath(), violation.getMessage())).collect(Collectors.joining(", "))
);
}
private String joinViolations(String a, String b) {
return String.join(", ", a, b);
}

private void throwException(String it) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, ErrorMessages.INVALID_INPUT + ": " + it);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package iris.client_bff.core.mail;

import io.vavr.control.Try;
import iris.client_bff.core.EmailAddress;
import iris.client_bff.core.mail.EmailTemplates.EmailType;
import iris.client_bff.core.mail.EmailTemplates.Key;
import iris.client_bff.core.model.EmailAddress;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package iris.client_bff.core;
package iris.client_bff.core.model;

import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package iris.client_bff.core.model;

import static org.apache.commons.lang3.StringUtils.*;

/**
* @author Jens Kutzsche
*/
public interface FlexibleEnum {

static String cleanStringForEnum(String string) {

var cleanString = replaceChars(string, '-', '_');
cleanString = camelToSnake(cleanString);

return cleanString.toUpperCase();
}

static String camelToSnake(String str) {
return str.replaceAll("([a-z])([A-Z]+)", "$1_$2").toLowerCase();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package iris.client_bff.core.model;

import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;

import java.util.regex.Pattern;

import javax.persistence.Column;
import javax.persistence.Embeddable;

import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
* @author Oliver Drotbohm
*/
@Embeddable
@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
public class PhoneNumber {

private static final String REMOVABLE_CHARACTERS_REGEX = "\\(\\)\\s\\-";
private static final String REMOVABLE_CHARACTERS_SET = "[" + REMOVABLE_CHARACTERS_REGEX + "]";
public static final String PATTERN = "^[\\+\\(\\)\\s\\-0-9]*?$";
private static final Pattern REGEX = Pattern.compile(PATTERN);

private final @Column(name = "phoneNumber") String value;

public static PhoneNumber of(String number) {

Assert.hasText(number, "Phone number must not be null or empty!");

if (!isValid(number)) {
throw new IllegalArgumentException(String.format("%s is not a valid phone number!", number));
}

return new PhoneNumber(number.replaceAll("\\s", "")
.replace("(0)", "")
.replaceAll(REMOVABLE_CHARACTERS_SET, "")
.replace("+", "00")
.replaceAll("^0049", "0"));
}

@Nullable
@SuppressWarnings("null")
public static PhoneNumber ofNullable(@Nullable String number) {
return StringUtils.hasText(number) ? of(number) : null;
}

public static boolean isValid(@Nullable String candidate) {
return StringUtils.hasText(candidate) && REGEX.matcher(candidate).matches();
}

/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package iris.client_bff.core.validation;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;

import iris.client_bff.core.validation.PhoneNumber.PhoneNumberValidator;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;

import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;

@Target({ METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = PhoneNumberValidator.class)
@Documented
public @interface PhoneNumber {

String message() default "{iris.validation.constraints.PhoneNumber.message}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

public static class PhoneNumberValidator implements ConstraintValidator<PhoneNumber, String> {

private PhoneNumberUtil util = PhoneNumberUtil.getInstance();

@Override
public boolean isValid(final String text, final ConstraintValidatorContext context) {

if (text == null) {
return true;
}

try {

var number = util.parse(text, "DE");
return util.isValidNumber(number);

} catch (NumberParseException e) {
return false;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
package iris.client_bff.events;

import io.vavr.control.Try;
import iris.client_bff.core.EmailAddress;
import iris.client_bff.core.mail.EmailProvider;
import iris.client_bff.core.mail.EmailSender;
import iris.client_bff.core.mail.EmailSender.TemplatedEmail.ConfiguredRecipient;
import iris.client_bff.core.model.EmailAddress;
import iris.client_bff.core.mail.EmailTemplates;
import lombok.AccessLevel;
import lombok.Setter;
Expand Down
Loading

0 comments on commit 6fa4277

Please sign in to comment.