Skip to content

Commit

Permalink
[VAS-825] feat: Introduced getTemplates API and related client and un…
Browse files Browse the repository at this point in the history
…it tests
  • Loading branch information
alessio-cialini committed Apr 22, 2024
1 parent eb3295f commit 0a87c3b
Show file tree
Hide file tree
Showing 13 changed files with 382 additions and 25 deletions.
167 changes: 166 additions & 1 deletion openapi/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,153 @@
}
} ]
},
"/notices/templates" : {
"get" : {
"tags" : [ "Notice Templates APIs" ],
"summary" : "getTemplates",
"description" : "Return available templates for notice generation",
"operationId" : "getTemplates",
"responses" : {
"200" : {
"description" : "Return template data",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : {
"schema" : {
"type" : "array",
"items" : {
"$ref" : "#/components/schemas/TemplateResource"
}
}
}
}
},
"400" : {
"description" : "Bad Request",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
"401" : {
"description" : "Unauthorized",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
}
},
"403" : {
"description" : "Forbidden",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
}
},
"404" : {
"description" : "Templates not found",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
"429" : {
"description" : "Too many requests",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
}
},
"500" : {
"description" : "Service error",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/ProblemJson"
}
}
}
},
"503" : {
"description" : "Service or template table unavailable",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
"schema" : {
"type" : "string"
}
}
},
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/ProblemJson"
}
}
}
}
},
"security" : [ {
"ApiKey" : [ ]
} ]
},
"parameters" : [ {
"name" : "X-Request-Id",
"in" : "header",
"description" : "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.",
"schema" : {
"type" : "string"
}
} ]
},
"/notices/templates/{template_id}" : {
"get" : {
"tags" : [ "Notice Templates APIs" ],
Expand Down Expand Up @@ -352,7 +499,7 @@
}
},
"404" : {
"description" : "Folder not found or unavailable for the requirer",
"description" : "Template not found",
"headers" : {
"X-Request-Id" : {
"description" : "This header identifies the call",
Expand Down Expand Up @@ -569,6 +716,24 @@
}
}
},
"TemplateResource" : {
"required" : [ "description", "templateExampleUrl", "templateId" ],
"type" : "object",
"properties" : {
"templateId" : {
"type" : "string",
"description" : "templateId, to use when requiring generation of a notice with the selected template"
},
"description" : {
"type" : "string",
"description" : "Template description"
},
"templateExampleUrl" : {
"type" : "string",
"description" : "Template example url"
}
}
},
"GetGenerationRequestStatusResource" : {
"required" : [ "noticesInError", "processedNotices", "status" ],
"type" : "object",
Expand Down
12 changes: 8 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,14 @@
<groupId>com.azure.spring</groupId>
<artifactId>spring-cloud-azure-starter-storage-blob</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-data-tables</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.kafka.test.context.EmbeddedKafka;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
Expand All @@ -10,6 +11,7 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import it.gov.pagopa.payment.notices.service.model.GetGenerationRequestStatusResource;
import it.gov.pagopa.payment.notices.service.model.ProblemJson;
import it.gov.pagopa.payment.notices.service.model.TemplateResource;
import it.gov.pagopa.payment.notices.service.service.NoticeGenerationService;
import it.gov.pagopa.payment.notices.service.service.NoticeTemplateService;
import it.gov.pagopa.payment.notices.service.util.OpenApiTableMetadata;
Expand All @@ -27,6 +29,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

/**
* Rest Controller containing APIs for generation request management
Expand All @@ -45,9 +48,47 @@ public NoticeTemplatesController(NoticeTemplateService noticeTemplateService) {
}

/**
*
* @param templateId
* @return
* Retrieve available notice templates.
* @return list of available templates inside the storage
*/
@Operation(summary = "getTemplates",
description = "Return available templates for notice generation",
security = {@SecurityRequirement(name = "ApiKey")})
@OpenApiTableMetadata(readWriteIntense = OpenApiTableMetadata.ReadWrite.READ,
cacheable = true, external = true, internal = false)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Return template data",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
array = @ArraySchema(schema = @Schema(implementation = TemplateResource.class)))),
@ApiResponse(responseCode = "400", description = "Bad Request",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ProblemJson.class))),
@ApiResponse(responseCode = "401",
description = "Unauthorized", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "403",
description = "Forbidden", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "404", description = "Templates not found",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ProblemJson.class))),
@ApiResponse(responseCode = "429",
description = "Too many requests", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "500",
description = "Service error", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ProblemJson.class))),
@ApiResponse(responseCode = "503",
description = "Service or template table unavailable",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ProblemJson.class)))
})
@GetMapping()
public List<TemplateResource> getTemplates() {
return noticeTemplateService.getTemplates();
}

/**
* Retrieve notice template zip, if available inside the template storage.
* @param templateId templateId to use for recovery
* @return template zipped data
*/
@Operation(summary = "getTemplate",
description = "Return templates",
Expand All @@ -65,7 +106,7 @@ public NoticeTemplatesController(NoticeTemplateService noticeTemplateService) {
description = "Unauthorized", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "403",
description = "Forbidden", content = @Content(schema = @Schema())),
@ApiResponse(responseCode = "404", description = "Folder not found or unavailable for the requirer",
@ApiResponse(responseCode = "404", description = "Template not found",
content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ProblemJson.class))),
@ApiResponse(responseCode = "429",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public enum AppError {
"Template Storage client temporarily not available"),
TEMPLATE_CLIENT_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Template Client Error",
"Template Client encountered an error"),

TEMPLATE_TABLE_CLIENT_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Template Table Client Error",
"Template Table Client encountered an error"),
FOLDER_NOT_AVAILABLE(HttpStatus.NOT_FOUND, "Folder Not Available",
"Required folder is either missing or not available to the requirer"),
ERROR_ON_MASSIVE_GENERATION_REQUEST(HttpStatus.INTERNAL_SERVER_ERROR,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package it.gov.pagopa.payment.notices.service.model;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class TemplateResource {

@Schema(description = "templateId, to use when requiring generation of a notice with the selected template", requiredMode = Schema.RequiredMode.REQUIRED)
private String templateId;
@Schema(description = "Template description", requiredMode = Schema.RequiredMode.REQUIRED)
private String description;
@Schema(description = "Template example url", requiredMode = Schema.RequiredMode.REQUIRED)
private String templateExampleUrl;

}
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
package it.gov.pagopa.payment.notices.service.service;

import it.gov.pagopa.payment.notices.service.model.TemplateResource;

import java.io.File;
import java.util.List;

/**
* Service interface for template management
*/
public interface NoticeTemplateService {

/**
* Retrieve list of available templates
* @return list of templates available for notice generation
*/
List<TemplateResource> getTemplates();

/**
* Recover the template file referring to the provided templateId
* @param templateId id to be used to retrieve the template
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package it.gov.pagopa.payment.notices.service.service.impl;

import it.gov.pagopa.payment.notices.service.model.TemplateResource;
import it.gov.pagopa.payment.notices.service.service.NoticeTemplateService;
import it.gov.pagopa.payment.notices.service.storage.NoticeTemplateStorageClient;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.List;

@Service
public class NoticeTemplateServiceImpl implements NoticeTemplateService {
Expand All @@ -15,6 +17,11 @@ public NoticeTemplateServiceImpl(NoticeTemplateStorageClient noticeTemplateStora
this.noticeTemplateStorageClient = noticeTemplateStorageClient;
}

@Override
public List<TemplateResource> getTemplates() {
return noticeTemplateStorageClient.getTemplates();
}

@Override
public File getTemplate(String templateId) {
return noticeTemplateStorageClient.getTemplate(templateId);
Expand Down
Loading

0 comments on commit 0a87c3b

Please sign in to comment.