diff --git a/mock-identity-system/pom.xml b/mock-identity-system/pom.xml
index d7d39db4..2f3a5e74 100644
--- a/mock-identity-system/pom.xml
+++ b/mock-identity-system/pom.xml
@@ -138,6 +138,41 @@
+
+
+ com.networknt
+ json-schema-validator
+ 1.5.1
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.12.1
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.12.1
+
+
+ com.fasterxml.jackson.core
+ jackson-annotations
+ 2.12.1
+
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/controller/IdentityController.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/controller/IdentityController.java
index a75e5cb2..12871f0c 100644
--- a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/controller/IdentityController.java
+++ b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/controller/IdentityController.java
@@ -5,18 +5,28 @@
*/
package io.mosip.esignet.mock.identitysystem.controller;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
import javax.validation.Valid;
import io.mosip.esignet.mock.identitysystem.dto.*;
+import io.mosip.esignet.mock.identitysystem.dto.Error;
+import io.mosip.esignet.mock.identitysystem.validator.IdentitySchema;
+import io.mosip.kernel.core.exception.ErrorResponse;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import io.mosip.esignet.mock.identitysystem.exception.MockIdentityException;
import io.mosip.esignet.mock.identitysystem.service.IdentityService;
import io.mosip.esignet.mock.identitysystem.util.HelperUtil;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
@RestController
@@ -29,7 +39,7 @@ public class IdentityController {
@PostMapping(value = "identity", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseWrapper createIdentity
- (@Valid @RequestBody RequestWrapper requestWrapper) throws MockIdentityException {
+ (@RequestBody @Valid RequestWrapper requestWrapper) throws MockIdentityException {
ResponseWrapper response = new ResponseWrapper();
IdentityStatus identityStatus = new IdentityStatus();
@@ -43,7 +53,7 @@ public class IdentityController {
@PutMapping(value = "identity", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseWrapper updateIdentity
- (@Valid @RequestBody RequestWrapper requestWrapper) throws MockIdentityException {
+ (@RequestBody @Valid RequestWrapper requestWrapper) throws MockIdentityException {
ResponseWrapper response = new ResponseWrapper();
IdentityStatus identityStatus = new IdentityStatus();
@@ -74,4 +84,25 @@ public ResponseWrapper createVerifiedClaim(@Valid @RequestB
return response;
}
+
+ @ExceptionHandler(ConstraintViolationException.class)
+ public ResponseEntity handleMethodArgumentNotValidException(ConstraintViolationException ex) {
+ List errors = new ArrayList<>();
+ if(ex != null) {
+ Set> violations = ((ConstraintViolationException) ex).getConstraintViolations();
+ for(ConstraintViolation> cv : violations) {
+ errors.add(new Error(cv.getMessage(), cv.getPropertyPath().toString() + ": " + cv.getMessage()));
+ }
+ return new ResponseEntity(getResponseWrapper(errors), HttpStatus.OK);
+ }
+ return ResponseEntity.status(HttpStatus.BAD_REQUEST)
+ .body(errors);
+ }
+
+ private ResponseWrapper getResponseWrapper(List errors) {
+ ResponseWrapper responseWrapper = new ResponseWrapper<>();
+ responseWrapper.setResponseTime(HelperUtil.getCurrentUTCDateTime());
+ responseWrapper.setErrors(errors);
+ return responseWrapper;
+ }
}
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/CreateIdentity.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/CreateIdentity.java
index bf646aeb..9c91b8db 100644
--- a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/CreateIdentity.java
+++ b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/CreateIdentity.java
@@ -5,8 +5,8 @@
*/
package io.mosip.esignet.mock.identitysystem.dto;
-import io.mosip.esignet.mock.identitysystem.validator.IdData;
+import io.mosip.esignet.mock.identitysystem.validator.IdentitySchema;
-@IdData(action = "CREATE")
+@IdentitySchema(action = "CREATE")
public class CreateIdentity extends IdentityData {
}
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/IdentityData.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/IdentityData.java
index 58c50a26..a4928f89 100644
--- a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/IdentityData.java
+++ b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/IdentityData.java
@@ -8,18 +8,13 @@
import java.util.List;
-import javax.validation.constraints.NotBlank;
-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import io.mosip.esignet.mock.identitysystem.util.ErrorConstants;
-import io.mosip.esignet.mock.identitysystem.validator.IdData;
import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class IdentityData {
-
- @NotBlank(message = ErrorConstants.INVALID_INDIVIDUAL_ID)
+
String individualId;
String pin;
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/UpdateIdentity.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/UpdateIdentity.java
index d5325270..f891bc95 100644
--- a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/UpdateIdentity.java
+++ b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/dto/UpdateIdentity.java
@@ -5,8 +5,8 @@
*/
package io.mosip.esignet.mock.identitysystem.dto;
-import io.mosip.esignet.mock.identitysystem.validator.IdData;
+import io.mosip.esignet.mock.identitysystem.validator.IdentitySchema;
-@IdData(action = "UPDATE")
+@IdentitySchema(action = "UPDATE")
public class UpdateIdentity extends IdentityData {
}
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/util/ErrorConstants.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/util/ErrorConstants.java
index f903b905..910e0361 100644
--- a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/util/ErrorConstants.java
+++ b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/util/ErrorConstants.java
@@ -40,4 +40,5 @@ public class ErrorConstants {
public static final String INVALID_TRUST_FRAMEWORK = "invalid_trust_framework";
public static final String INVALID_VERIFIED_DATE = "invalid_verified_date";
public static final String CLAIM_ALREADY_EXISTS="Claim already exists";
+ public static final String INVALID_IDENTITY_DATA= "invalid_identity_data";
}
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdData.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdData.java
deleted file mode 100644
index d4829155..00000000
--- a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdData.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package io.mosip.esignet.mock.identitysystem.validator;
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-import static io.mosip.esignet.mock.identitysystem.util.ErrorConstants.INVALID_REQUEST;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-import javax.validation.Constraint;
-import javax.validation.Payload;
-
-@Target({TYPE})
-@Retention(RUNTIME)
-@Constraint(validatedBy = IdentityDataValidator.class)
-@Documented
-public @interface IdData {
-
- String message() default INVALID_REQUEST;
-
- Class>[] groups() default {};
-
- Class extends Payload>[] payload() default {};
-
- String action() default "CREATE";
-
-}
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentityDataValidator.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentityDataValidator.java
deleted file mode 100644
index 9ced35b3..00000000
--- a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentityDataValidator.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/.
- */
-package io.mosip.esignet.mock.identitysystem.validator;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import io.mosip.esignet.mock.identitysystem.dto.IdentityData;
-
-@Component
-public class IdentityDataValidator implements ConstraintValidator {
-
- @Value("#{T(java.util.Arrays).asList('${mosip.mock.identity.create.required.fields:}')}")
- private List createRequiredFields;
-
- @Value("#{T(java.util.Arrays).asList('${mosip.mock.identity.update.required.fields:}')}")
- private List updateRequiredFields;
-
- private String action;
-
- @Override
- public void initialize(IdData constraintAnnotation) {
- this.action = constraintAnnotation.action();
- }
-
- @Override
- public boolean isValid(IdentityData value, ConstraintValidatorContext context) {
- if (value == null) {
- return false;
- }
-
- @SuppressWarnings("unchecked")
- Map fields = new ObjectMapper().convertValue(value, HashMap.class);
-
- fields.values().removeIf(Objects::isNull);
-
- return fields.keySet().containsAll(this.action.equals("UPDATE") ? updateRequiredFields : createRequiredFields);
- }
-
-}
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentitySchema.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentitySchema.java
new file mode 100644
index 00000000..27ef0caa
--- /dev/null
+++ b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentitySchema.java
@@ -0,0 +1,23 @@
+package io.mosip.esignet.mock.identitysystem.validator;
+
+
+import io.mosip.esignet.mock.identitysystem.util.ErrorConstants;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE_USE, ElementType.FIELD, ElementType.PARAMETER})
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = IdentitySchemaValidator.class)
+public @interface IdentitySchema {
+
+ String message() default ErrorConstants.INVALID_IDENTITY_DATA;
+ Class>[] groups() default {};
+ Class extends Payload>[] payload() default {};
+
+ String action();
+}
diff --git a/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentitySchemaValidator.java b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentitySchemaValidator.java
new file mode 100644
index 00000000..301b0fb1
--- /dev/null
+++ b/mock-identity-system/src/main/java/io/mosip/esignet/mock/identitysystem/validator/IdentitySchemaValidator.java
@@ -0,0 +1,109 @@
+package io.mosip.esignet.mock.identitysystem.validator;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.networknt.schema.*;
+import io.mosip.esignet.mock.identitysystem.dto.IdentityData;
+import io.mosip.esignet.mock.identitysystem.dto.RequestWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.jose4j.lang.StringUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.stereotype.Component;
+
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class IdentitySchemaValidator implements ConstraintValidator {
+
+ @Value("${mosip.mock.ida.identity.schema.url}")
+ private String identitySchemaUrl;
+
+ @Value("#{${mosip.mock.ida.update-identity.non-mandatory.fields}}")
+ private Set nonMandatoryFieldsOnUpdate;
+
+ private String action;
+
+ private volatile JsonSchema schema;
+
+ @Autowired
+ ObjectMapper objectMapper;
+
+ @Autowired
+ ResourceLoader resourceLoader;
+
+
+ @Override
+ public void initialize(IdentitySchema constraintAnnotation) {
+ this.action = constraintAnnotation.action();
+ }
+
+ @Override
+ public boolean isValid(Object object, ConstraintValidatorContext context) {
+
+ if (!(object instanceof IdentityData)) {
+ return false;
+ }
+ IdentityData identityData=(IdentityData) object;
+ JsonNode identityJsonNode = objectMapper.valueToTree(identityData);
+ Set validationErrors = validateIdentityData(identityJsonNode);
+
+ // Handle validation errors
+ if (!validationErrors.isEmpty()) {
+ addValidationErrorCode(validationErrors,context);
+ return false;
+ }
+ return true;
+ }
+
+ private Set validateIdentityData(JsonNode identityJsonNode) {
+ Set errors = getSchema().validate(identityJsonNode);
+ // If not a create operation, filter out specific errors
+ if (action.equals("UPDATE")) {
+ // Ignore validation errors with code 1029 (null value) and for exempted fields when validating updateIdentity
+ errors = errors.stream()
+ .filter(error -> !error.getCode().equals("1029") ||
+ !nonMandatoryFieldsOnUpdate.contains(error.
+ getInstanceLocation().getName(0)))
+ .collect(Collectors.toSet());
+ }
+ return errors;
+ }
+
+ private void addValidationErrorCode(Set errors, ConstraintValidatorContext context) {
+ context.disableDefaultConstraintViolation();
+ errors.forEach(error->context.
+ buildConstraintViolationWithTemplate("invalid_"+error.getInstanceLocation().getName(0).toLowerCase())
+ .addConstraintViolation());
+ }
+
+ private JsonSchema getSchema() {
+ if(schema !=null ) return schema;
+ synchronized (this) {
+ if (schema == null) {
+ InputStream schemaResponse = getResource(identitySchemaUrl);
+ JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
+ schema = jsonSchemaFactory.getSchema(schemaResponse);
+ }
+ }
+ return schema;
+ }
+
+ private InputStream getResource(String url) {
+ try{
+ Resource resource = resourceLoader.getResource(url);
+ return resource.getInputStream();
+ }catch (IOException e){
+ log.error("Failed to parse data: {}", url, e);
+ }
+ throw new RuntimeException("invalid_configuration");
+ }
+}
diff --git a/mock-identity-system/src/main/resources/application-default.properties b/mock-identity-system/src/main/resources/application-default.properties
index 0a123419..0254df88 100644
--- a/mock-identity-system/src/main/resources/application-default.properties
+++ b/mock-identity-system/src/main/resources/application-default.properties
@@ -103,12 +103,10 @@ spring.jpa.hibernate.ddl-auto=none
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
mosip.esignet.mock.authenticator.ida.otp-channels=email,phone
-mosip.mock.identity.create.required.fields=individualId,fullName,givenName,familyName,gender,dateOfBirth,email,phone,streetAddress,locality,region,postalCode,country
-mosip.mock.identity.update.required.fields=individualId
mosip.esignet.mock.supported-fields=individualId,pin,givenName,familyName,gender,dateOfBirth,email,phone,streetAddress,locality,region,postalCode,country
mosip.mock.ida.kba.default.field-language=eng
-mosip.mock.ida.kyc.psut.field=psut
+
#Related to health check of hsm
mosip.kernel.keymgr.hsm.health.check.enabled=false
diff --git a/mock-identity-system/src/main/resources/bootstrap.properties b/mock-identity-system/src/main/resources/bootstrap.properties
index 08225801..f5ea042c 100644
--- a/mock-identity-system/src/main/resources/bootstrap.properties
+++ b/mock-identity-system/src/main/resources/bootstrap.properties
@@ -1,7 +1,8 @@
spring.application.name=mock-identity-system
#spring.cloud.config.uri=http://localhost:8888
spring.profiles.active=default,local
-
+#spring.cloud.config.label=master
+spring.cloud.config.name=mock-identity-system
spring.main.allow-bean-definition-overriding=true
server.port=8082
diff --git a/mock-identity-system/src/main/resources/mock-identity-schema.json b/mock-identity-system/src/main/resources/mock-identity-schema.json
new file mode 100644
index 00000000..41081997
--- /dev/null
+++ b/mock-identity-system/src/main/resources/mock-identity-schema.json
@@ -0,0 +1,248 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "$defs": {
+ "langField": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "language": {
+ "type": "string"
+ },
+ "value": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "language",
+ "value"
+ ],
+ "additionalProperties": false
+ }
+ }
+ },
+ "properties": {
+ "individualId": {
+ "type": "string",
+ "pattern": "^[0-9]{5,19}$"
+ },
+ "fullName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "givenName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "familyName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "middleName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "nickName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "preferredUsername": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "gender": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,20}|^[ء-ي\\s\\u0621-\\u064A\\u0660-\\u0669\\u0671-\\u06BF\\uFE70-\\uFEFF\\u0600-\\u06FFگچپژیلفقهمو ء-ي]{1,20}$)$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "streetAddress": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ0-9\\s.,°№-]{1,200}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ0-9]{1,200})$"
+
+ }
+ }
+ }
+ }
+ ]
+ },
+ "locality": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ0-9\\s.,°№-]{1,200}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ0-9]{1,200})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "region": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ0-9\\s.,°№-]{1,200}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ0-9]{1,200})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "country": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,20}|^[ء-ي\\s\\u0621-\\u064A\\u0660-\\u0669\\u0671-\\u06BF\\uFE70-\\uFEFF\\u0600-\\u06FFگچپژیلفقهمو ء-ي]{1,20}$)$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "pin": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "preferredLang": {
+ "type": "string"
+ },
+ "dateOfBirth": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "postalCode": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "encodedPhoto": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$"
+ },
+ "phone": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "zoneInfo": {
+ "type": "string"
+ },
+ "locale": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "password": {
+ "type": "string",
+ "pattern": "\\S"
+ }
+ },
+ "required": [
+ "individualId",
+ "fullName",
+ "givenName",
+ "familyName",
+ "middleName",
+ "nickName",
+ "preferredUsername",
+ "gender",
+ "streetAddress",
+ "locality",
+ "region",
+ "country",
+ "pin",
+ "preferredLang",
+ "dateOfBirth",
+ "postalCode",
+ "encodedPhoto",
+ "email",
+ "phone",
+ "zoneInfo",
+ "locale",
+ "password"
+ ],
+ "additionalProperties": false
+}
\ No newline at end of file
diff --git a/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/controller/IdentityControllerTest.java b/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/controller/IdentityControllerTest.java
index aa78f333..9bb9f19c 100644
--- a/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/controller/IdentityControllerTest.java
+++ b/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/controller/IdentityControllerTest.java
@@ -19,7 +19,6 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.mosip.esignet.mock.identitysystem.dto.*;
-import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,7 +30,6 @@
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.mosip.esignet.mock.identitysystem.service.IdentityService;
@@ -56,12 +54,40 @@ public class IdentityControllerTest {
@Before
public void init() {
identityRequest = new IdentityData();
- identityRequest.setIndividualId("123456789");
+ identityRequest.setIndividualId("826741183");
identityRequest.setEmail("test@gmail.com");
+
+ List preferredNameList =new ArrayList<>();
+ LanguageValue engLangValue= new LanguageValue();
+ engLangValue.setValue("Siddharth K Mansour");
+ engLangValue.setLanguage("eng");
+ LanguageValue arabicLangValue= new LanguageValue();
+ arabicLangValue.setLanguage("ara");
+ arabicLangValue.setValue("سيدارت ك منصور");
+ preferredNameList.add(engLangValue);
+ preferredNameList.add(arabicLangValue);
+ identityRequest.setFullName(preferredNameList);
+ identityRequest.setPreferredUsername(preferredNameList);
+ identityRequest.setFamilyName(preferredNameList);
+ identityRequest.setGivenName(preferredNameList);
+ identityRequest.setPreferredUsername(preferredNameList);
+ identityRequest.setNickName(preferredNameList);
+ identityRequest.setPreferredUsername(preferredNameList);
+ identityRequest.setMiddleName(preferredNameList);
+
+ LanguageValue mockLang = new LanguageValue();
+ mockLang.setLanguage("eng");
+ mockLang.setValue("mock");
+ identityRequest.setGender(Arrays.asList(mockLang));
+ identityRequest.setStreetAddress(Arrays.asList(mockLang));
+ identityRequest.setLocality(Arrays.asList(mockLang));
+ identityRequest.setRegion(Arrays.asList(mockLang));
+
LanguageValue langValue = new LanguageValue();
langValue.setLanguage("eng");
langValue.setValue("ind");
identityRequest.setCountry(Arrays.asList(langValue));
+
identityRequest.setDateOfBirth("20021990");
identityRequest.setEncodedPhoto("testencodedphoto");
identityRequest.setGender(Arrays.asList(langValue));
@@ -74,6 +100,10 @@ public void init() {
identityRequest.setFamilyName(Arrays.asList(langValue));
identityRequest.setStreetAddress(Arrays.asList(langValue));
identityRequest.setPhone("9090909090");
+ identityRequest.setPreferredLang("eng");
+ identityRequest.setZoneInfo("local");
+ identityRequest.setLocale("eng");
+ identityRequest.setPassword("mock-password");
}
@Test
@@ -86,7 +116,7 @@ public void createIdentity_withValidIdentity_returnSuccessResponse() throws Exce
Mockito.doNothing().when(identityService).addIdentity(identityRequest);
mockMvc.perform(post("/identity").content(objectMapper.writeValueAsString(requestWrapper))
- .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+ .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.response.status").value("mock identity data created successfully"));
}
@@ -101,17 +131,59 @@ public void createIdentity_withInvalidIdentity_returnErrorResponse() throws Exce
Mockito.doNothing().when(identityService).addIdentity(identityRequest);
mockMvc.perform(post("/identity").content(objectMapper.writeValueAsString(requestWrapper))
- .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+ .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+ .andExpect(jsonPath("$.errors").isNotEmpty())
+ .andExpect(jsonPath("$.errors[0].errorCode").value("invalid_individualid"));
+ }
+
+ @Test
+ public void createIdentity_withInvalidNameAndLocale_returnErrorResponse() throws Exception {
+ RequestWrapper requestWrapper = new RequestWrapper();
+ ZonedDateTime requestTime = ZonedDateTime.now(ZoneOffset.UTC);
+ requestWrapper.setRequestTime(requestTime.format(DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN)));
+ identityRequest.setFullName(null);
+ identityRequest.setLocale(null);
+ requestWrapper.setRequest(identityRequest);
+
+ Mockito.doNothing().when(identityService).addIdentity(identityRequest);
+ mockMvc.perform(post("/identity").content(objectMapper.writeValueAsString(requestWrapper))
+ .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+ .andExpect(jsonPath("$.errors").isNotEmpty())
+ .andExpect(jsonPath("$.errors.size()").value(2));
+ }
+
+ @Test
+ public void createIdentity_withInvalidFullName_returnErrorResponse() throws Exception {
+ RequestWrapper requestWrapper = new RequestWrapper();
+ ZonedDateTime requestTime = ZonedDateTime.now(ZoneOffset.UTC);
+ requestWrapper.setRequestTime(requestTime.format(DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN)));
+
+ List nameList=new ArrayList<>();
+ LanguageValue engLangValue= new LanguageValue();
+ engLangValue.setValue("Siddharth K سيدارت");
+ engLangValue.setLanguage("eng");
+ LanguageValue arabicLangValue= new LanguageValue();
+ arabicLangValue.setLanguage("ara");
+ arabicLangValue.setValue("سيدارت ك منصور");
+ nameList.add(engLangValue);
+ nameList.add(arabicLangValue);
+ identityRequest.setFullName(nameList);
+ requestWrapper.setRequest(identityRequest);
+
+ Mockito.doNothing().when(identityService).addIdentity(identityRequest);
+ mockMvc.perform(post("/identity").content(objectMapper.writeValueAsString(requestWrapper))
+ .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.errors").isNotEmpty())
- .andExpect(jsonPath("$.errors[*].errorCode").value(Matchers.containsInAnyOrder(ErrorConstants.INVALID_REQUEST, ErrorConstants.INVALID_INDIVIDUAL_ID)));
+ .andExpect(jsonPath("$.errors[0].errorCode").value("invalid_fullname"));
}
-
+
@Test
public void getIdentity_withValidId_returnSuccessResponse() throws Exception {
+ identityRequest.setIndividualId("123456789");
Mockito.when(identityService.getIdentity(Mockito.anyString())).thenReturn(identityRequest);
mockMvc.perform(get("/identity/{individualId}", "123456789")
- .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+ .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.response.individualId").value("123456789"));
}
@@ -178,4 +250,19 @@ public void updateIdentity_withValidIdentity_thenPass() throws Exception {
.andExpect(jsonPath("$.response.status").value("mock Identity data updated successfully"));
}
+ @Test
+ public void updateIdentity_withInValidIdentity_thenFail() throws Exception {
+ RequestWrapper requestWrapper = new RequestWrapper();
+ ZonedDateTime requestTime = ZonedDateTime.now(ZoneOffset.UTC);
+ requestWrapper.setRequestTime(requestTime.format(DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN)));
+ identityRequest.setFullName(null);
+ requestWrapper.setRequest(identityRequest);
+
+ Mockito.doNothing().when(identityService).updateIdentity(identityRequest);
+ mockMvc.perform(put("/identity").content(objectMapper.writeValueAsString(requestWrapper))
+ .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
+ .andExpect(jsonPath("$.errors").isNotEmpty())
+ .andExpect(jsonPath("$.errors[0].errorCode").value("invalid_fullname"));
+ }
+
}
diff --git a/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/validator/ValidatorTest.java b/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/validator/ValidatorTest.java
index c487e737..07dd4deb 100644
--- a/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/validator/ValidatorTest.java
+++ b/mock-identity-system/src/test/java/io/mosip/esignet/mock/identitysystem/validator/ValidatorTest.java
@@ -35,8 +35,6 @@ public class ValidatorTest {
private static final String UTC_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
- @InjectMocks
- private IdentityDataValidator identityDataValidator;
@Test
public void requestTimeValidator_withNullValue_thenFail() {
@@ -68,49 +66,4 @@ public void testIsValid_ValidDateJustOutsideNegativeVariation() {
assertFalse(requestTimeValidator.isValid(validDate, context));
}
- @Test
- public void identityDataValidator_withNullValue_thenFail() {
- assertFalse(identityDataValidator.isValid(null, context));
- }
-
- @Test
- public void identityDataValidator_withValidInputForCreateAction_thenPass() {
- List supportedFields = Arrays.asList("fullName", "email", "phone");
- ReflectionTestUtils.setField(identityDataValidator, "action", "CREATE");
- ReflectionTestUtils.setField(identityDataValidator, "createRequiredFields", supportedFields);
- IdentityData identityData = new IdentityData();
- LanguageValue languageValue = new LanguageValue();
- languageValue.setLanguage("en");
- languageValue.setValue("John Doe");
-
- identityData.setFullName(List.of(languageValue));
- identityData.setEmail("john.doe@example.com");
- identityData.setPhone("1234567890");
- identityData.setEncodedPhoto("encoded-photo");
-
- assertTrue(identityDataValidator.isValid(identityData, context));
- }
-
- @Test
- public void identityDataValidator_withValidInputForUpdateAction_thenPass() {
- List supportedFields = Arrays.asList("individualId");
- ReflectionTestUtils.setField(identityDataValidator, "action", "UPDATE");
- ReflectionTestUtils.setField(identityDataValidator, "updateRequiredFields", supportedFields);
- IdentityData identityData = new IdentityData();
- identityData.setIndividualId("individualId");
-
- assertTrue(identityDataValidator.isValid(identityData, context));
- }
-
- @Test
- public void identityDataValidator_withInvalidInputForUpdateAction_thenFail() {
- List supportedFields = Arrays.asList("individualId", "email");
- ReflectionTestUtils.setField(identityDataValidator, "action", "UPDATE");
- ReflectionTestUtils.setField(identityDataValidator, "updateRequiredFields", supportedFields);
- IdentityData identityData = new IdentityData();
- identityData.setIndividualId("individualId");
-
- assertFalse(identityDataValidator.isValid(identityData, context));
- }
-
}
diff --git a/mock-identity-system/src/test/resources/application-test.properties b/mock-identity-system/src/test/resources/application-test.properties
new file mode 100644
index 00000000..5408cc3a
--- /dev/null
+++ b/mock-identity-system/src/test/resources/application-test.properties
@@ -0,0 +1,3 @@
+
+mosip.mock.ida.identity.schema.url=classpath:/mock-identity-test-schema.json
+mosip.mock.ida.update-identity.non-mandatory.fields={"givenName","familyName","middleName","nickName","preferredUsername","gender","streetAddress","locality","region","country","pin","preferredLang","dateOfBirth","postalCode","encodedPhoto","email","phone","zoneInfo","locale","password"}
diff --git a/mock-identity-system/src/test/resources/bootstrap.properties b/mock-identity-system/src/test/resources/bootstrap.properties
new file mode 100644
index 00000000..b78f2069
--- /dev/null
+++ b/mock-identity-system/src/test/resources/bootstrap.properties
@@ -0,0 +1,2 @@
+
+spring.profiles.active=test
\ No newline at end of file
diff --git a/mock-identity-system/src/test/resources/mock-identity-test-schema.json b/mock-identity-system/src/test/resources/mock-identity-test-schema.json
new file mode 100644
index 00000000..41081997
--- /dev/null
+++ b/mock-identity-system/src/test/resources/mock-identity-test-schema.json
@@ -0,0 +1,248 @@
+{
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "object",
+ "$defs": {
+ "langField": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "language": {
+ "type": "string"
+ },
+ "value": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "language",
+ "value"
+ ],
+ "additionalProperties": false
+ }
+ }
+ },
+ "properties": {
+ "individualId": {
+ "type": "string",
+ "pattern": "^[0-9]{5,19}$"
+ },
+ "fullName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "givenName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "familyName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "middleName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "nickName": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "preferredUsername": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,40}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ]{1,40})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "gender": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,20}|^[ء-ي\\s\\u0621-\\u064A\\u0660-\\u0669\\u0671-\\u06BF\\uFE70-\\uFEFF\\u0600-\\u06FFگچپژیلفقهمو ء-ي]{1,20}$)$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "streetAddress": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ0-9\\s.,°№-]{1,200}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ0-9]{1,200})$"
+
+ }
+ }
+ }
+ }
+ ]
+ },
+ "locality": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ0-9\\s.,°№-]{1,200}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ0-9]{1,200})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "region": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ0-9\\s.,°№-]{1,200}|[ء-ي\\s-٩ٱ-ڿﹰ-\uFEFF\u0600-ۿ0-9]{1,200})$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "country": {
+ "allOf": [
+ { "$ref": "#/$defs/langField" },
+ {
+ "items": {
+ "properties": {
+ "value": {
+ "pattern": "^(?:[a-zA-ZÀ-ÿ\\s]{1,20}|^[ء-ي\\s\\u0621-\\u064A\\u0660-\\u0669\\u0671-\\u06BF\\uFE70-\\uFEFF\\u0600-\\u06FFگچپژیلفقهمو ء-ي]{1,20}$)$"
+ }
+ }
+ }
+ }
+ ]
+ },
+ "pin": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "preferredLang": {
+ "type": "string"
+ },
+ "dateOfBirth": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "postalCode": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "encodedPhoto": {
+ "type": "string"
+ },
+ "email": {
+ "type": "string",
+ "pattern": "^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$"
+ },
+ "phone": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "zoneInfo": {
+ "type": "string"
+ },
+ "locale": {
+ "type": "string",
+ "pattern": "\\S"
+ },
+ "password": {
+ "type": "string",
+ "pattern": "\\S"
+ }
+ },
+ "required": [
+ "individualId",
+ "fullName",
+ "givenName",
+ "familyName",
+ "middleName",
+ "nickName",
+ "preferredUsername",
+ "gender",
+ "streetAddress",
+ "locality",
+ "region",
+ "country",
+ "pin",
+ "preferredLang",
+ "dateOfBirth",
+ "postalCode",
+ "encodedPhoto",
+ "email",
+ "phone",
+ "zoneInfo",
+ "locale",
+ "password"
+ ],
+ "additionalProperties": false
+}
\ No newline at end of file