Skip to content

Commit

Permalink
[INJICERT-495] Added public end points, entity and repository for svg…
Browse files Browse the repository at this point in the history
… rendering template implementation (#107)

* [INJICERT-495] Added implementation for serving svg render template through public endpoint

Signed-off-by: Piyush7034 <[email protected]>

* Added last modified in svg template cache

Signed-off-by: Piyush7034 <[email protected]>

* Added template config for inserting templates on application boot

Signed-off-by: Piyush7034 <[email protected]>

* [INJICERT-495] Added tests for template repository and service

Signed-off-by: Piyush7034 <[email protected]>

* Chnage UUID to a specific name for referring the template

Signed-off-by: Piyush7034 <[email protected]>

* Added changes for the review comments

Signed-off-by: Piyush7034 <[email protected]>

* Added static uuid for fetching template

Signed-off-by: Piyush7034 <[email protected]>

* Added createdtimes and updatedtimes for svg template table

Signed-off-by: Piyush7034 <[email protected]>

* Fixed test failure issue

Signed-off-by: Piyush7034 <[email protected]>

* Change in fetch template config in template config

Signed-off-by: Piyush7034 <[email protected]>

* Changed db name to svg_template

Signed-off-by: Piyush7034 <[email protected]>

* Removed old and commented code

Signed-off-by: Piyush7034 <[email protected]>

---------

Signed-off-by: Piyush7034 <[email protected]>
  • Loading branch information
Piyush7034 authored Oct 17, 2024
1 parent 0f593f0 commit 8ea41bb
Show file tree
Hide file tree
Showing 20 changed files with 429 additions and 4 deletions.
8 changes: 8 additions & 0 deletions certify-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,13 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ public class ErrorConstants {
public static final String PROOF_HEADER_INVALID_KEY = "proof_header_invalid_key";
public static final String PROOF_HEADER_AMBIGUOUS_KEY = "proof_header_ambiguous_key";
public static final String UNSUPPORTED_OPENID_VERSION = "unsupported_openid4vci_draft_version";
public static final String INVALID_TEMPLATE_ID = "template_with_id_not_found";
public static final String EMPTY_TEMPLATE_CONTENT = "empty_template_content";
public static final String EMPTY_TEMPLATE_NAME = "empty_template_name";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.certify.core.entity;

import io.mosip.certify.core.constants.ErrorConstants;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.UUID;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class SvgTemplate {
@Id
private UUID id;

@NotBlank(message = ErrorConstants.EMPTY_TEMPLATE_CONTENT)
@Column(name = "template")
private String template;

@Column(name = "cr_dtimes")
private LocalDateTime createdtimes;

@Column(name = "upd_dtimes")
private LocalDateTime updatedtimes;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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.certify.core.repository;

import io.mosip.certify.core.entity.SvgTemplate;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.UUID;

public interface SvgTemplateRepository extends JpaRepository<SvgTemplate, UUID> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* 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.certify.core.spi;

import io.mosip.certify.core.entity.SvgTemplate;

import java.util.UUID;

public interface SvgTemplateService {
SvgTemplate getSvgTemplate(UUID id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
import org.springframework.web.client.RestTemplate;

@Configuration
@EnableJpaRepositories(basePackages = {"io.mosip.kernel.keymanagerservice.repository"})
@EntityScan(basePackages = {"io.mosip.kernel.keymanagerservice.entity"})
@EnableJpaRepositories(basePackages = {"io.mosip.certify.core.repository", "io.mosip.kernel.keymanagerservice.repository"})
@EntityScan(basePackages = {"io.mosip.certify.core.entity", "io.mosip.kernel.keymanagerservice.entity"})
@Slf4j
public class AppConfig implements ApplicationRunner {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* 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/.
*/

/* This is for temporary purpose till an API isn’t added to simplify Issuer onboarding. */

package io.mosip.certify.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.mosip.certify.core.entity.SvgTemplate;
import io.mosip.certify.core.exception.CertifyException;
import io.mosip.certify.core.repository.SvgTemplateRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.*;


@Configuration
@Slf4j
public class TemplateConfig implements CommandLineRunner {
@Autowired
SvgTemplateRepository svgRenderTemplateRepository;

@Value("${mosip.certify.svg-templates}")
private String svgTemplateJson;

@Autowired
private ObjectMapper objectMapper;

@Autowired
private RestTemplate restTemplate;

@Override
public void run(String... args) throws Exception {
String svgTemplateContent = "";
List<Object> svgTemplateMap;
Resource resource = new ClassPathResource(svgTemplateJson);
try {
svgTemplateContent = (Files.readString(resource.getFile().toPath()));
} catch (IOException e) {
log.error("Missing local json file for referring svg templates", e);
}

if(!svgTemplateContent.isEmpty()) {
try {
svgTemplateMap = objectMapper.readValue(svgTemplateContent, List.class);
} catch (JsonProcessingException e) {
throw new CertifyException("Missing configuration for svg template content " + e.getMessage());
}

List<SvgTemplate> svgRenderTemplates = svgRenderTemplateRepository.findAll();

if(svgRenderTemplates.isEmpty()) {
svgTemplateMap.forEach((value) -> {
SvgTemplate svgRenderTemplate = new SvgTemplate();
LinkedHashMap<String, Object> valueMap = (LinkedHashMap<String, Object>) value;
UUID id = UUID.fromString(valueMap.get("id").toString());
svgRenderTemplate.setId(id);
String templateURI = valueMap.get("content").toString();
if(templateURI.startsWith("http")) {
String templateFromUrl = restTemplate.getForObject(templateURI, String.class);
svgRenderTemplate.setTemplate(templateFromUrl);
} else {
svgRenderTemplate.setTemplate(templateURI);
}
LocalDateTime localDateTime = LocalDateTime.now();
svgRenderTemplate.setCreatedtimes(localDateTime);
svgRenderTemplate.setUpdatedtimes(localDateTime);
log.info("Template inserted in svg template table.");
svgRenderTemplateRepository.save(svgRenderTemplate);
});
}
}
log.info("=============== CERTIFY TEMPLATE SETUP COMPLETED ===============");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* 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.certify.controller;

import io.mosip.certify.core.entity.SvgTemplate;
import io.mosip.certify.core.exception.CertifyException;
import io.mosip.certify.core.spi.SvgTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.ZoneId;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/public")
public class SvgTemplateController {
@Autowired
SvgTemplateService svgTemplateService;

@GetMapping("/svg-template/{id}")
public ResponseEntity<String> serveSvgTemplate(@PathVariable UUID id) throws CertifyException {
SvgTemplate template = svgTemplateService.getSvgTemplate(id);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, "image/svg")
.cacheControl(CacheControl.maxAge(1, TimeUnit.DAYS).cachePublic())
.lastModified(template.getUpdatedtimes().atZone(ZoneId.systemDefault()).toInstant())
.body(template.getTemplate());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.certify.services;

import io.mosip.certify.core.constants.ErrorConstants;
import io.mosip.certify.core.entity.SvgTemplate;
import io.mosip.certify.core.exception.CertifyException;
import io.mosip.certify.core.repository.SvgTemplateRepository;
import io.mosip.certify.core.spi.SvgTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Optional;
import java.util.UUID;

@Slf4j
@Component
public class SvgTemplateServiceImpl implements SvgTemplateService {
@Autowired
SvgTemplateRepository svgRenderTemplateRepository;


@Override
public SvgTemplate getSvgTemplate(UUID id) {
Optional<SvgTemplate> optional = svgRenderTemplateRepository.findById(id);
SvgTemplate svgRenderTemplate = optional.orElseThrow(() -> new CertifyException(ErrorConstants.INVALID_TEMPLATE_ID));

return svgRenderTemplate;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mosip.certify.security.ignore-csrf-urls=**/actuator/**,/favicon.ico,**/error,\
**/issuance/**,**/system-info/**

mosip.certify.security.ignore-auth-urls=/actuator/**,**/error,**/swagger-ui/**,\
**/v3/api-docs/**, **/issuance/**,/system-info/**
**/v3/api-docs/**, **/issuance/**,/system-info/**,/public/**


## ------------------------------------------ Discovery openid-configuration -------------------------------------------
Expand Down Expand Up @@ -171,6 +171,7 @@ mosip.certify.key-values={\
}}\
}\
}
mosip.certify.svg-templates=svg-template.json

## ------------------------------------------- Integrations ------------------------------------------------------------
#mosip.certify.integration.scan-base-package=io.mosip.certify.sunbirdrc.integration
Expand Down
6 changes: 6 additions & 0 deletions certify-service/src/main/resources/svg-template.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{
"id": "5b9c2a12-810a-7388-2dc8-13ee7ad88bac",
"content": "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"250\" height=\"400\" viewBox=\"0 0 250 400\">\n <defs>\n <linearGradient id=\"gradient\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n <stop offset=\"0%\" style=\"stop-color:#91d9e3;stop-opacity:1\" />\n <stop offset=\"100%\" style=\"stop-color:#ffA500;stop-opacity:1\" />\n </linearGradient>\n <clipPath id=\"rounded-clip\">\n <rect width=\"100%\" height=\"100%\" rx=\"15\" ry=\"15\" />\n </clipPath>\n </defs>\n <!-- Background rectangle with rounded corners -->\n <rect width=\"100%\" height=\"100%\" fill=\"url(#gradient)\" rx=\"15\" ry=\"15\" />\n \n <!-- Main image clipped with rounded corners -->\n \n <!-- QR Code -->\n <image \n x=\"170\" \n y=\"15\" \n width=\"70\" \n height=\"70\" \n xlink:href=\"data:image/png;base64\" \n clip-path=\"url(#rounded-clip)\" \n />\n \n <!-- Other images and text elements -->\n <image \n x=\"5\" \n y=\"-15\" \n width=\"50\" \n height=\"50\" \n xlink:href=\"https://sunbird.org/images/sunbird-logo-new.png\" \n clip-path=\"url(#rounded-clip)\" \n />\n <image \n x=\"70\" \n y=\"70\" \n width=\"100\" \n height=\"100\" \n xlink:href=\"https://83b8-2401-4900-1cd1-a419-6154-ee6-76a4-466.ngrok-free.app/profile_photo.png\" \n clip-path=\"url(#rounded-clip)\" \n />\n <text x=\"20\" y=\"200\" fill=\"#000000\" font-size=\"16\" font-weight=\"bold\">{{credentialSubject/policyName}}</text>\n <text x=\"80\" y=\"220\" fill=\"#0000ff\" font-size=\"18\" font-weight=\"bold\">{{credentialSubject/policyNumber}}</text>\n <text x=\"20\" y=\"240\" fill=\"#000000\" font-size=\"16\" font-weight=\"bold\">{{credentialSubject/fullName}}</text>\n <text x=\"20\" y=\"260\" fill=\"#000000\" font-size=\"12\" font-weight=\"normal\">{{credentialSubject/gender}}</text>\n <text x=\"20\" y=\"280\" fill=\"#000000\" font-size=\"12\" font-weight=\"normal\">{{credentialSubject/email}}</text>\n <text x=\"20\" y=\"300\" fill=\"#000000\" font-size=\"12\" font-weight=\"normal\">{{credentialSubject/mobile}}</text>\n\n <text x=\"5\" y=\"350\" fill=\"#000000\" font-size=\"12\" font-weight=\"normal\">Policy Issued On</text>\n <text x=\"5\" y=\"370\" fill=\"#0000ff\" font-size=\"12\" font-weight=\"normal\">{{credentialSubject/policyIssuedOn}}</text>\n\n <text x=\"150\" y=\"350\" fill=\"#000000\" font-size=\"12\" font-weight=\"normal\">Policy Expires On</text>\n <text x=\"150\" y=\"370\" fill=\"#0000ff\" font-size=\"12\" font-weight=\"normal\">{{credentialSubject/policyExpiresOn}}</text>\n\n <text x=\"5\" y=\"350\" fill=\"#000000\" font-size=\"12\" font-weight=\"normal\">Issuance Date On</text>\n <text x=\"5\" y=\"370\" fill=\"#0000ff\" font-size=\"12\" font-weight=\"normal\">{{issuanceDate}}</text>\n\n <text x=\"150\" y=\"350\" fill=\"#000000\" font-size=\"12\" font-weight=\"normal\">Expiration Date On</text>\n <text x=\"150\" y=\"370\" fill=\"#0000ff\" font-size=\"12\" font-weight=\"normal\">{{expirationDate}}</text>\n</svg>"
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.mosip.certify.repository;

import io.mosip.certify.core.entity.SvgTemplate;
import io.mosip.certify.core.repository.SvgTemplateRepository;
import jakarta.validation.ConstraintViolationException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.UUID;

@RunWith(SpringRunner.class)
@DataJpaTest
public class SvgRenderTemplateRepositoryTest {
@Autowired
private SvgTemplateRepository svgRenderTemplateRepository;

@Test
public void insertSvgTemplate_withValidDetail_thenPass() {
SvgTemplate svgRenderTemplate = new SvgTemplate();
String template = """
<svg xmlns=\\"http://www.w3.org/2000/svg\\" width=\\"200\\" height=\\"200\\">
<rect width=\\"200\\" height=\\"200\\" fill=\\"#ff6347\\"/>
<text x=\\"100\\" y=\\"100\\" font-size=\\"30\\" text-anchor=\\"middle\\" fill=\\"white\\">
Hello, SVG!
</text></svg>
""";
UUID id = UUID.randomUUID();
svgRenderTemplate.setId(id);
svgRenderTemplate.setTemplate(template);
svgRenderTemplate.setCreatedtimes(LocalDateTime.now());

svgRenderTemplate = svgRenderTemplateRepository.saveAndFlush(svgRenderTemplate);
Assert.assertNotNull(svgRenderTemplate);

Optional<SvgTemplate> optional = svgRenderTemplateRepository.findById(svgRenderTemplate.getId());
Assert.assertTrue(optional.isPresent());
Assert.assertEquals(svgRenderTemplate.getTemplate(), optional.get().getTemplate());
}

@Test
public void insertSvgTemplate_withEmptyTemplate_thenFail() {
SvgTemplate svgRenderTemplate = new SvgTemplate();
svgRenderTemplate.setId(UUID.randomUUID());
svgRenderTemplate.setTemplate("");
svgRenderTemplate.setCreatedtimes(LocalDateTime.now());

ConstraintViolationException e = Assertions.assertThrows(
ConstraintViolationException.class, () -> svgRenderTemplateRepository.saveAndFlush(svgRenderTemplate)
);

Assert.assertTrue(e.getConstraintViolations().stream()
.anyMatch( v -> v.getPropertyPath().toString().equals("template")));
}
}
Loading

0 comments on commit 8ea41bb

Please sign in to comment.