Skip to content

Commit

Permalink
Merge pull request #516 from tw-mosip/injiweb-1106-car-theme-changes
Browse files Browse the repository at this point in the history
[INJIWEB-1106]: multi lingual support for credential download as pdf
  • Loading branch information
vijay151096 authored Nov 19, 2024
2 parents fab09be + 49d19f4 commit e6f185f
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ public ResponseEntity<?> downloadCredentialAsPDF(
try {
String issuerId = params.get("issuer");
String credentialType = params.get("credential");
String locale = params.get("locale");

logger.info("Initiated Token Call");
TokenResponseDTO response = credentialService.getTokenResponse(params, issuerId);

logger.info("Initiated Download Credential Call");
ByteArrayInputStream inputStream = credentialService.downloadCredentialAsPDF(issuerId, credentialType, response);
ByteArrayInputStream inputStream = credentialService.downloadCredentialAsPDF(issuerId, credentialType, response, locale);

return ResponseEntity
.ok()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@

public interface CredentialService {
TokenResponseDTO getTokenResponse(Map<String, String> params, String issuerId) throws ApiNotAccessibleException, IOException;
ByteArrayInputStream downloadCredentialAsPDF(String issuerId, String credentialType, TokenResponseDTO response) throws Exception;
ByteArrayInputStream downloadCredentialAsPDF(String issuerId, String credentialType, TokenResponseDTO response, String locale) throws Exception;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import io.mosip.mimoto.util.Utilities;
import io.mosip.pixelpass.PixelPass;
import jakarta.annotation.PostConstruct;
import jakarta.validation.Valid;
import lombok.NoArgsConstructor;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
Expand Down Expand Up @@ -112,14 +113,14 @@ public TokenResponseDTO getTokenResponse(Map<String, String> params, String issu
}

@Override
public ByteArrayInputStream downloadCredentialAsPDF(String issuerId, String credentialType, TokenResponseDTO response) throws Exception {
public ByteArrayInputStream downloadCredentialAsPDF(String issuerId, String credentialType, TokenResponseDTO response, String locale) throws Exception {
IssuerDTO issuerConfig = issuerService.getIssuerConfig(issuerId);
CredentialIssuerWellKnownResponse credentialIssuerWellKnownResponse = issuerService.getIssuerWellknown(issuerId);
CredentialsSupportedResponse credentialsSupportedResponse = issuerService.getIssuerWellknownForCredentialType(issuerId, credentialType);
VCCredentialRequest vcCredentialRequest = generateVCCredentialRequest(issuerConfig, credentialIssuerWellKnownResponse, credentialsSupportedResponse, response.getAccess_token());
VCCredentialResponse vcCredentialResponse = downloadCredential(credentialIssuerWellKnownResponse.getCredentialEndPoint(), vcCredentialRequest, response.getAccess_token());
String dataShareUrl = QRCodeType.OnlineSharing.equals(issuerConfig.getQr_code_type()) ? dataShareService.storeDataInDataShare(objectMapper.writeValueAsString(vcCredentialResponse)) : "";
return generatePdfForVerifiableCredentials(vcCredentialResponse, issuerConfig, credentialsSupportedResponse, dataShareUrl);
return generatePdfForVerifiableCredentials(issuerId, credentialType, vcCredentialResponse, issuerConfig, credentialsSupportedResponse, dataShareUrl, locale);
}

public VCCredentialResponse downloadCredential(String credentialEndpoint, VCCredentialRequest vcCredentialRequest, String accessToken) throws InvalidCredentialResourceException {
Expand All @@ -145,20 +146,24 @@ public VCCredentialRequest generateVCCredentialRequest(IssuerDTO issuerDTO, Cred
.build();
}

public ByteArrayInputStream generatePdfForVerifiableCredentials(VCCredentialResponse vcCredentialResponse, IssuerDTO issuerDTO, CredentialsSupportedResponse credentialsSupportedResponse, String dataShareUrl) throws Exception {
LinkedHashMap<String, Object> displayProperties = loadDisplayPropertiesFromWellknown(vcCredentialResponse, credentialsSupportedResponse);
Map<String, Object> data = getPdfResourceFromVcProperties(displayProperties, credentialsSupportedResponse, vcCredentialResponse, issuerDTO, dataShareUrl);
return renderVCInCredentialTemplate(data);
public ByteArrayInputStream generatePdfForVerifiableCredentials(String issuerId, String credentialType, VCCredentialResponse vcCredentialResponse, IssuerDTO issuerDTO, CredentialsSupportedResponse credentialsSupportedResponse, String dataShareUrl, String locale) throws Exception {
LinkedHashMap<String, Object> displayProperties = loadDisplayPropertiesFromWellknown(vcCredentialResponse, credentialsSupportedResponse, locale);
Map<String, Object> data = getPdfResourceFromVcProperties(displayProperties, credentialsSupportedResponse, vcCredentialResponse, issuerDTO, dataShareUrl, locale);
return renderVCInCredentialTemplate(data, issuerId, credentialType);
}

@NotNull
private static LinkedHashMap<String, Object> loadDisplayPropertiesFromWellknown(VCCredentialResponse vcCredentialResponse, CredentialsSupportedResponse credentialsSupportedResponse) {
private static LinkedHashMap<String, Object> loadDisplayPropertiesFromWellknown(VCCredentialResponse vcCredentialResponse, CredentialsSupportedResponse credentialsSupportedResponse, String locale) {
LinkedHashMap<String,Object> displayProperties = new LinkedHashMap<>();
Map<String, Object> credentialProperties = vcCredentialResponse.getCredential().getCredentialSubject();

LinkedHashMap<String, String> vcPropertiesFromWellKnown = new LinkedHashMap<>();
Map<String, CredentialDisplayResponseDto> credentialSubject = credentialsSupportedResponse.getCredentialDefinition().getCredentialSubject();
credentialSubject.keySet().forEach(VCProperty -> vcPropertiesFromWellKnown.put(VCProperty, credentialSubject.get(VCProperty).getDisplay().get(0).getName()));
credentialSubject.keySet().forEach(VCProperty -> {
Optional<@Valid CredentialIssuerDisplayResponse> filteredResponse = credentialSubject.get(VCProperty).getDisplay().stream().filter(obj -> obj.getLocale().equals(locale)).findFirst();
String filteredValue = filteredResponse.isPresent() ? filteredResponse.get().getName() : "" ;
vcPropertiesFromWellKnown.put(VCProperty, filteredValue);
});

List<String> orderProperty = credentialsSupportedResponse.getOrder();

Expand All @@ -172,7 +177,7 @@ private static LinkedHashMap<String, Object> loadDisplayPropertiesFromWellknown(
}


private Map<String, Object> getPdfResourceFromVcProperties(LinkedHashMap<String, Object> displayProperties, CredentialsSupportedResponse credentialsSupportedResponse, VCCredentialResponse vcCredentialResponse, IssuerDTO issuerDTO, String dataShareUrl) throws IOException, WriterException {
private Map<String, Object> getPdfResourceFromVcProperties(LinkedHashMap<String, Object> displayProperties, CredentialsSupportedResponse credentialsSupportedResponse, VCCredentialResponse vcCredentialResponse, IssuerDTO issuerDTO, String dataShareUrl, String locale) throws IOException, WriterException {
Map<String, Object> data = new HashMap<>();
LinkedHashMap<String, Object> rowProperties = new LinkedHashMap<>();
String backgroundColor = credentialsSupportedResponse.getDisplay().get(0).getBackgroundColor();
Expand All @@ -190,7 +195,8 @@ private Map<String, Object> getPdfResourceFromVcProperties(LinkedHashMap<String,
if( ((List<?>) entry.getValue()).get(0) instanceof String) {
value = ((List<String>) entry.getValue()).stream().reduce((field1, field2) -> field1 + ", " + field2 ).get();
} else {
value = (String) ((Map<?, ?>) ((List<?>) entry.getValue()).get(0)).get("value");
Optional<Map<?, ?>> valueMap = ((List<Map<?, ?>>) entry.getValue()).stream().filter(obj -> obj.get("language").equals(locale)).findFirst();
value = valueMap.isPresent() ? valueMap.get().get("value").toString() : "" ;
}
rowProperties.put(entry.getKey(), value);
} else {
Expand All @@ -212,8 +218,8 @@ private Map<String, Object> getPdfResourceFromVcProperties(LinkedHashMap<String,
}

@NotNull
private ByteArrayInputStream renderVCInCredentialTemplate(Map<String, Object> data) throws IOException {
String credentialTemplate = utilities.getCredentialSupportedTemplateString();
private ByteArrayInputStream renderVCInCredentialTemplate(Map<String, Object> data, String issuerId, String credentialType) throws IOException {
String credentialTemplate = utilities.getCredentialSupportedTemplateString(issuerId, credentialType);

Properties props = new Properties();
props.setProperty("resource.loader", "class");
Expand Down
10 changes: 3 additions & 7 deletions src/main/java/io/mosip/mimoto/util/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,11 @@ public class Utilities {
@Value("${mosip.openid.verifiers}")
private String trustedVerifiers;

@Value("${mosip.openid.htmlTemplate}")
private String getCredentialSupportedHtml;

private String issuersConfigJsonString = null;

private String trustedVerifiersJsonString = null;

private String credentialTemplateHtmlString = null;


// uncomment for running mimoto Locally to populate the issuers json
// public Utilities(@Value("classpath:mimoto-issuers-config.json") Resource resource,
Expand Down Expand Up @@ -173,9 +170,8 @@ public String getTrustedVerifiersJsonValue() {
return (trustedVerifiersJsonString != null && !trustedVerifiersJsonString.isEmpty()) ?
trustedVerifiersJsonString : getJson(configServerFileStorageURL, trustedVerifiers);
}
public String getCredentialSupportedTemplateString() {
return (credentialTemplateHtmlString != null && !credentialTemplateHtmlString.isEmpty()) ?
credentialTemplateHtmlString : getJson(configServerFileStorageURL, getCredentialSupportedHtml);
public String getCredentialSupportedTemplateString(String issuerId, String credentialType) {
return getJson(configServerFileStorageURL, String.format("%s-%s-template.html",issuerId, credentialType));
}
public static ResponseWrapper<Object> handleExceptionWithErrorCode(Exception exception) {
String errorMessage = exception.getMessage();
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application-local.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ server.port=8099
server.servlet.context-path=/v1/mimoto
health.config.enabled=false
mosip.service.end-points=/**/*
keycloak.internal.url=

mosipbox.public.url=http://localhost:${server.port}
mosip.api.public.url=http://localhost:${server.port}
Expand Down Expand Up @@ -209,7 +210,6 @@ mosip.otp.download.enable=false
mosip.openid.issuers=mimoto-issuers-config.json

mosip.openid.issuer.credentialSupported=/wellKnownIssuer/Insurance.json
mosip.openid.htmlTemplate=credential-template.html
mosip.oidc.client.assertion.type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
mosip.oidc.p12.filename=oidckeystore.p12
mosip.oidc.p12.password=mosip123
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html>
<head>
<meta charset="UTF-8" />
<title>Identity Card</title>
<title>New Template Identity Card </title>
</head>
<body #if ($textColor) style="color: $textColor;" #end>
<div #if ($backgroundColor) style="background: $backgroundColor; border: 1px $textolor solid; border-radius: 15px; padding: 10px;" #else style="border: 2px black solid; border-radius: 15px; padding: 10px;" #end>
Expand Down Expand Up @@ -35,5 +35,12 @@
</div>
<img src="data:image/png;base64,$qrCodeImage" alt="QR Code"/>
</div>
<div style="display: flex; width: 100%; padding: 8px; border-radius: 8px; border: 2px solid #f6dfbe; background-color: #FFF7E5; margin: 32px 0;">
#if ($credentialValidity != -1)
<div style="padding: 0 16px; text-align: center; color: #8B6105; font-size: 14px;">Please note: This credential is limited to a maximum of $credentialValidity verifications by authorized verifiers. Once the specified number of verifications has been reached, this credential will no longer be valid for further verification attempts.</div>
#else
<div style="padding: 0 16px; text-align: center; color: #8B6105; font-size: 14px;">Please note: This credential can be used for verification by authorized verifiers without any limit on the number of verifications. It provides continuous, secure access for credential validation.</div>
#end
</div>
</body>
</html>

0 comments on commit e6f185f

Please sign in to comment.