Skip to content

Commit

Permalink
[INJIWEB-43] refractored v2 apis to existing controller (#188)
Browse files Browse the repository at this point in the history
* [INJIWEB-43]added inji web apis
Signed-off-by: Challarao <[email protected]>

* [INJIWEB-43]added header for custom file name for pdf download
Signed-off-by: Challarao <[email protected]>

* [INJIWEB-43] fix dto naming to camel case and change route  for credential supported API
Signed-off-by: Challarao <[email protected]>

* [INJIWEB-43] changed exception handling for credential types
Signed-off-by: Challarao <[email protected]>
  • Loading branch information
challabeehyv committed Mar 28, 2024
1 parent 65d1140 commit 015f1de
Show file tree
Hide file tree
Showing 27 changed files with 1,180 additions and 20 deletions.
12 changes: 8 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,17 +89,16 @@
<bouncycastle.version>1.70</bouncycastle.version>
<jwt.version> 3.8.1</jwt.version>
<google.zxing.version>3.3.3</google.zxing.version>
<itextcore.version>7.2.0</itextcore.version>
<itexthtml2pdf.version>2.0.0</itexthtml2pdf.version>
<itextcore.version>8.0.3</itextcore.version>
<itexthtml2pdf.version>5.0.3</itexthtml2pdf.version>
<itext.version>5.5.13</itext.version>
<commons-math3>3.6.1</commons-math3>
<commons-lang3>3.7</commons-lang3>
<commons-io>2.11.0</commons-io>
<commons-codec>1.15</commons-codec>
<swagger.version>2.9.2</swagger.version>
<springdoc.version>1.5.10</springdoc.version>


<jjwt-version>0.9.1</jjwt-version>
<sonar.coverage.exclusions>
**/constant/**,**/config/**,**/httpfilter/**,**/cache/**,**/dto/**,**/entity/**,**/model/**,**/exception/**,**/repository/**,**/security/**,**/*Config.java,**/*BootApplication.java,**/*VertxApplication.java,**/cbeffutil/**,**/core.http/**,**/util/**
</sonar.coverage.exclusions>
Expand Down Expand Up @@ -365,6 +364,11 @@
<artifactId>nimbus-jose-jwt</artifactId>
<version>9.25.6</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt-version}</version>
</dependency>
<dependency>
<groupId>org.bitbucket.b_c</groupId>
<artifactId>jose4j</artifactId>
Expand Down
93 changes: 89 additions & 4 deletions src/main/java/io/mosip/mimoto/controller/IssuersController.java
Original file line number Diff line number Diff line change
@@ -1,46 +1,62 @@
package io.mosip.mimoto.controller;

import io.mosip.mimoto.core.http.ResponseWrapper;
import io.mosip.mimoto.dto.DisplayDTO;
import io.mosip.mimoto.dto.ErrorDTO;
import io.mosip.mimoto.dto.IssuerDTO;
import io.mosip.mimoto.dto.IssuersDTO;
import io.mosip.mimoto.dto.mimoto.CredentialIssuerWellKnownResponse;
import io.mosip.mimoto.dto.mimoto.CredentialSupportedDisplayResponse;
import io.mosip.mimoto.dto.mimoto.CredentialsSupportedResponse;
import io.mosip.mimoto.dto.mimoto.IssuerSupportedCredentialsResponse;
import io.mosip.mimoto.exception.ApiNotAccessibleException;
import io.mosip.mimoto.service.IssuersService;
import io.mosip.mimoto.util.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Optional;

import static io.mosip.mimoto.exception.PlatformErrorMessages.API_NOT_ACCESSIBLE_EXCEPTION;
import static io.mosip.mimoto.exception.PlatformErrorMessages.INVALID_CREDENTIAL_TYPE_EXCEPTION;
import static io.mosip.mimoto.exception.PlatformErrorMessages.INVALID_ISSUER_ID_EXCEPTION;
import static io.mosip.mimoto.exception.PlatformErrorMessages.MIMOTO_PDF_SIGN_EXCEPTION;

@RestController
@RequestMapping(value = "/issuers")
public class IssuersController {
@Autowired
IssuersService issuersService;

private static final String defaultLanguageConstant = "en";

private static final String ID = "mosip.mimoto.issuers";

private final Logger logger = LoggerFactory.getLogger(IssuersController.class);

@GetMapping()
public ResponseEntity<Object> getAllIssuers() {
public ResponseEntity<Object> getAllIssuers(@RequestParam(required = false) String search) {
ResponseWrapper<IssuersDTO> responseWrapper = new ResponseWrapper<>();
responseWrapper.setId(ID);
responseWrapper.setVersion("v1");
responseWrapper.setResponsetime(DateUtils.getRequestTimeString());
try {
responseWrapper.setResponse(issuersService.getAllIssuers());
responseWrapper.setResponse(issuersService.getAllIssuers(search));
} catch (ApiNotAccessibleException | IOException e) {
logger.error("Exception occurred while fetching issuers ", e);
responseWrapper.setErrors(List.of(new ErrorDTO(API_NOT_ACCESSIBLE_EXCEPTION.getCode(), API_NOT_ACCESSIBLE_EXCEPTION.getMessage())));
Expand Down Expand Up @@ -78,4 +94,73 @@ public ResponseEntity<Object> getIssuerConfig(@PathVariable("issuer-id") String
return ResponseEntity.status(HttpStatus.OK).body(responseWrapper);
}

@GetMapping("/{issuer-id}/credentialTypes")
public ResponseEntity<Object> getCredentialTypes(@PathVariable("issuer-id") String issuerId,
@RequestParam(required = false) String search) {
ResponseWrapper<Object> responseWrapper = new ResponseWrapper<>();
responseWrapper.setId(ID);
responseWrapper.setVersion("v1");
responseWrapper.setResponsetime(DateUtils.getRequestTimeString());
IssuerSupportedCredentialsResponse credentialTypes;
try {
credentialTypes = issuersService.getCredentialsSupported(issuerId, search);
}catch (ApiNotAccessibleException | IOException exception){
logger.error("Exception occurred while fetching credential types", exception);
responseWrapper.setErrors(List.of(new ErrorDTO(API_NOT_ACCESSIBLE_EXCEPTION.getCode(), API_NOT_ACCESSIBLE_EXCEPTION.getMessage())));
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseWrapper);
}
responseWrapper.setResponse(credentialTypes);

if (credentialTypes.getSupportedCredentials() == null) {
logger.error("invalid issuer id passed - {}", issuerId);
responseWrapper.setErrors(List.of(new ErrorDTO(INVALID_ISSUER_ID_EXCEPTION.getCode(), INVALID_ISSUER_ID_EXCEPTION.getMessage())));
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(responseWrapper);
}

return ResponseEntity.status(HttpStatus.OK).body(responseWrapper);
}

@GetMapping("/{issuer-id}/credentials/{credentialType}/download")
public ResponseEntity<?> generatePdfForVC(@RequestHeader("Bearer") String token,
@PathVariable("issuer-id") String issuerId,
@PathVariable("credentialType") String credentialType) {

ResponseWrapper<Object> responseWrapper = new ResponseWrapper<>();
responseWrapper.setId(ID);
responseWrapper.setVersion("v1");
responseWrapper.setResponsetime(DateUtils.getRequestTimeString());

try{
IssuerDTO issuerConfig = issuersService.getIssuerConfig(issuerId);
CredentialIssuerWellKnownResponse credentialIssuerWellKnownResponse = issuersService.getCredentialWellKnownFromJson();
Optional<CredentialsSupportedResponse> credentialsSupportedResponse = credentialIssuerWellKnownResponse.getCredentialsSupported().stream()
.filter(credentialsSupported -> credentialsSupported.getId().equals(credentialType))
.findFirst();
if (credentialsSupportedResponse.isEmpty()){
logger.error("Invalid credential Type passed - {}", credentialType);
responseWrapper.setErrors(List.of(new ErrorDTO(INVALID_CREDENTIAL_TYPE_EXCEPTION.getCode(), INVALID_CREDENTIAL_TYPE_EXCEPTION.getMessage())));
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseWrapper);
}
ByteArrayInputStream inputStream = issuersService.generatePdfForVerifiableCredentials(token, issuerConfig, credentialsSupportedResponse.get(), credentialIssuerWellKnownResponse.getCredentialEndPoint());
//PDF file name with issuer display name and credential type display name
String pdfFileName = issuerConfig.getDisplay().stream().filter(displayDTO -> defaultLanguageConstant.equals(displayDTO.getLanguage())).map(DisplayDTO::getName).findFirst().orElse(null) +
"_" + credentialsSupportedResponse.get().getDisplay().stream()
.filter(credentialSupportedDisplayResponse -> defaultLanguageConstant.equals(credentialSupportedDisplayResponse.getLocale())).map(CredentialSupportedDisplayResponse::getName).findFirst().orElse(null);
return ResponseEntity
.ok()
.contentType(MediaType.APPLICATION_PDF)
.header(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s.pdf", pdfFileName))
.header(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "Content-Disposition")
.body(new InputStreamResource(inputStream));
}catch (ApiNotAccessibleException | IOException exception){
logger.error("Exception occurred while fetching credential types ", exception);
responseWrapper.setErrors(List.of(new ErrorDTO(API_NOT_ACCESSIBLE_EXCEPTION.getCode(), API_NOT_ACCESSIBLE_EXCEPTION.getMessage())));
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(responseWrapper);
} catch (Exception exception) {
logger.error("Exception occurred while generating pdf ", exception);
responseWrapper.setErrors(List.of(new ErrorDTO(MIMOTO_PDF_SIGN_EXCEPTION.getCode(), MIMOTO_PDF_SIGN_EXCEPTION.getMessage())));
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(responseWrapper);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.mosip.mimoto.dto.mimoto;

import lombok.Data;

import java.util.List;
import java.util.Map;

@Data
public class CredentialDefinitionResponseDto {
private List<String> type;
private Map<String, CredentialDisplayResponseDto> credentialSubject;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.mosip.mimoto.dto.mimoto;

import lombok.Data;

import java.util.List;

@Data
public class CredentialDisplayResponseDto {
private List<CredentialIssuerDisplayResponse> display;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.mosip.mimoto.dto.mimoto;

import lombok.Data;

@Data
public class CredentialIssuerDisplayResponse {
private String name;
private String locale;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.mosip.mimoto.dto.mimoto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;
import lombok.Data;

import java.util.List;

@Data
public class CredentialIssuerWellKnownResponse {
@SerializedName("credential_issuer")
@JsonProperty("credential_issuer")
private String credentialIssuer;

@SerializedName("credential_endpoint")
@JsonProperty("credential_endpoint")
private String credentialEndPoint;

@SerializedName("credentials_supported")
@JsonProperty("credentials_supported")
private List<CredentialsSupportedResponse> credentialsSupported;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.mosip.mimoto.dto.mimoto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import io.mosip.mimoto.dto.LogoDTO;
import lombok.Data;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;

@Data
public class CredentialSupportedDisplayResponse {

@Expose
@NotBlank
String name;

@Expose
@Valid
LogoDTO logo;

@Expose
@NotBlank
String locale;

@JsonProperty("background_color")
@SerializedName("background_color")
@Expose
@NotBlank
String backgroundColor;

@JsonProperty("text_color")
@SerializedName("text_color")
@Expose
@NotBlank
String textColor;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.mosip.mimoto.dto.mimoto;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.gson.annotations.SerializedName;
import lombok.Data;

import java.util.List;

@Data
public class CredentialsSupportedResponse {
private String format;
private String id;
private String scope;

@SerializedName("proof_types_supported")
@JsonProperty("proof_types_supported")
private List<String> proofTypesSupported;

@SerializedName("credential_definition")
@JsonProperty("credential_definition")
private CredentialDefinitionResponseDto credentialDefinition;

private List<CredentialSupportedDisplayResponse> display;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.mosip.mimoto.dto.mimoto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;

@Data
public class IssuerSupportedCredentialsResponse {
@JsonProperty("authorization_endpoint")
private String authorizationEndPoint;
private List<CredentialsSupportedResponse> supportedCredentials;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.mosip.mimoto.dto.mimoto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;

@Data
@Builder
public class VCCredentialDefinition {

@JsonProperty("@context")
private List<@NotBlank String> context;

@NotEmpty
private List<@NotBlank String> type;

private Map<String, Object> credentialSubject;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package io.mosip.mimoto.dto.mimoto;

import lombok.Data;

@Data
public class VCCredentialIssueBody {
private VCCredentialProperties credential;
private String credentialSchemaId;
private String createdAt;
private String createdBy;
private String updatedAt;
private String updatedBy;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.mosip.mimoto.dto.mimoto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
import java.util.Map;

@Data
public class VCCredentialProperties {
private String issuer;

private String id;

private String issuanceDate;

private VCCredentialResponseProof proof;

private Map<String, Object> credentialSubject;

@JsonProperty("@context")
private Object context;

@NotEmpty
private List<@NotBlank String> type;
}
Loading

0 comments on commit 015f1de

Please sign in to comment.