diff --git a/api-docs/api-docs.yaml b/api-docs/api-docs.yaml new file mode 100644 index 0000000..427d6c3 --- /dev/null +++ b/api-docs/api-docs.yaml @@ -0,0 +1,381 @@ +openapi: 3.0.1 +info: + title: UCI Inbound + description: UCI Inbound Api Documentation + termsOfService: http://swagger.io/terms/ + license: + name: Apache 2.0 + url: http://springdoc.org + version: "1.0" +servers: +- url: http://localhost:8085 + description: Generated server url +paths: + /netcore/whatsApp: + post: + tags: + - Netcore Apis + summary: Send message to kafka topic via netcore whatsapp service + description: This API is used to get send message to inbound kafka topic received + from netcore whatsapp service. + operationId: netcoreWhatsApp + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/NetcoreMessageFormat' + examples: + Text Message: + description: Request body for text messages + value: + messages: + - message_id: ABEGkZlgQyWAAgo-sDVSUOa9jH0z + from: "919960432580" + received_at: "1567090835" + context: + ncmessage_id: null + message_id: null + message_type: TEXT + text_type: + text: Hi UCI + required: true + responses: + "200": + description: OK! + /gupshup/whatsApp: + post: + tags: + - Gupshup Apis + summary: Send message to kafka topic via gupshup whatsapp service + description: This API is used to get send message to inbound kafka topic received + from gupshup whatsapp service. + operationId: gupshupWhatsApp + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/GSWhatsAppMessage' + responses: + "200": + description: OK! + /service/health/kafka: + get: + tags: + - Services Health Api + summary: Get Kafka Health + description: This API is used to get kafka health status + operationId: kafkaStatusCheck + responses: + "200": + description: OK! + content: + application/json: + schema: + $ref: '#/components/schemas/ComponentHealthApiExample' + /service/health/cassandra: + get: + tags: + - Services Health Api + summary: Get Cassandra Health + description: This API is used to get cassandra health status + operationId: cassandraStatusCheck + responses: + "200": + description: OK! + content: + application/json: + schema: + $ref: '#/components/schemas/ComponentHealthApiExample' + /service/health/campaign: + get: + tags: + - Services Health Api + summary: Get Campaign Health + description: This API is used to get campaign health status + operationId: campaignUrlStatusCheck + responses: + "200": + description: OK! + content: + application/json: + schema: + $ref: '#/components/schemas/ComponentHealthApiExample' + /health: + get: + tags: + - System Health Apis + summary: Get System Health + description: |- + This API is used to get system health. It included health of two components. + - Kafka + - Cassandra + operationId: statusCheck + responses: + "200": + description: OK! + content: + application/json: + schema: + $ref: '#/components/schemas/SystemHealthApiExample' + /campaign/start: + get: + tags: + - Campaign Apis + summary: Start Campaign + description: This API is used to start the campaign kafka topic.- The fields + marked with an asterisk (*) are mandatory. They cannot be null or empty. + operationId: startCampaign + parameters: + - name: campaignId + in: query + required: true + schema: + type: string + responses: + "200": + description: OK + /campaign/resume: + get: + tags: + - Campaign Apis + summary: Resume Campaign + description: This API is used to start campaign kafka topic. + operationId: resumeCampaign + parameters: + - name: campaignId + in: query + required: true + schema: + type: string + responses: + "200": + description: OK + /campaign/pause: + get: + tags: + - Campaign Apis + summary: Pause Campaign + description: This API is used to pause the campaign kafka topic. + operationId: pauseCampaign + parameters: + - name: campaignId + in: query + required: true + schema: + type: string + responses: + "200": + description: OK +components: + schemas: + MessageContext: + type: object + properties: + ncmessage_id: + type: string + message_id: + type: string + NetcoreInboundFile: + type: object + properties: + mime_type: + type: string + signature: + type: string + url: + type: string + caption: + type: string + NetcoreMessageFormat: + type: object + properties: + messages: + type: array + items: + $ref: '#/components/schemas/NetcoreWhatsAppMessage' + NetcoreWhatsAppMessage: + type: object + properties: + waNumber: + type: string + mobile: + type: string + replyId: + type: string + messageId: + type: string + timestamp: + type: string + name: + type: string + version: + type: integer + format: int32 + type: + type: string + text: + $ref: '#/components/schemas/TextType' + eventType: + type: string + context: + $ref: '#/components/schemas/MessageContext' + statusRemark: + type: string + source: + type: string + image: + $ref: '#/components/schemas/NetcoreInboundFile' + document: + $ref: '#/components/schemas/NetcoreInboundFile' + voice: + $ref: '#/components/schemas/NetcoreInboundFile' + audio: + $ref: '#/components/schemas/NetcoreInboundFile' + video: + $ref: '#/components/schemas/NetcoreInboundFile' + location: + type: string + response: + type: string + extra: + type: string + app: + type: string + TextType: + type: object + properties: + text: + type: string + GSWhatsAppMessage: + type: object + properties: + waNumber: + type: string + mobile: + type: string + replyId: + type: string + messageId: + type: string + timestamp: + type: integer + format: int64 + name: + type: string + version: + type: integer + format: int32 + type: + type: string + text: + type: string + image: + $ref: '#/components/schemas/WAInboundFile' + document: + $ref: '#/components/schemas/WAInboundFile' + voice: + $ref: '#/components/schemas/WAInboundFile' + audio: + $ref: '#/components/schemas/WAInboundFile' + video: + $ref: '#/components/schemas/WAInboundFile' + location: + type: string + response: + type: string + extra: + type: string + app: + type: string + WAInboundFile: + type: object + properties: + mime_type: + type: string + signature: + type: string + url: + type: string + caption: + type: string + ComponentHealthApiExample: + type: object + properties: + id: + type: string + example: api.content.health + ver: + type: string + example: "3.0" + ts: + type: string + example: 2021-09-01T11:14:50Z + params: + $ref: '#/components/schemas/HealthApiParamsParameter' + responseCode: + type: string + example: OK + result: + $ref: '#/components/schemas/ComponentHealthApiResultParameter' + ComponentHealthApiResultParameter: + type: object + properties: + healthy: + type: boolean + example: true + HealthApiParamsParameter: + type: object + properties: + resmsgid: + type: string + example: 859fee0c-94d6-4a0d-b786-2025d763b78a + msgid: + type: string + example: "null" + err: + type: string + example: "null" + status: + type: string + example: Successful + errmsg: + type: string + example: "null" + HealthApiChecksParameter: + type: object + properties: + name: + type: string + example: Cassandra + healthy: + type: boolean + example: true + HealthApiResultParameter: + type: object + properties: + checks: + type: array + items: + $ref: '#/components/schemas/HealthApiChecksParameter' + healthy: + type: boolean + example: true + SystemHealthApiExample: + type: object + properties: + id: + type: string + example: api.content.health + ver: + type: string + example: "3.0" + ts: + type: string + example: 2021-09-01T11:14:50Z + params: + $ref: '#/components/schemas/HealthApiParamsParameter' + responseCode: + type: string + example: OK + result: + $ref: '#/components/schemas/HealthApiResultParameter' diff --git a/pom.xml b/pom.xml index ae45bec..1ea5e65 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ jaxb-impl 2.2.11 - + org.springframework.boot spring-boot-starter-test @@ -98,6 +98,11 @@ 1.0 compile + + org.springdoc + springdoc-openapi-ui + 1.5.2 + diff --git a/src/main/java/com/uci/inbound/AppConfigInbound.java b/src/main/java/com/uci/inbound/AppConfigInbound.java index 4706c8e..25ee8c6 100644 --- a/src/main/java/com/uci/inbound/AppConfigInbound.java +++ b/src/main/java/com/uci/inbound/AppConfigInbound.java @@ -1,14 +1,27 @@ package com.uci.inbound; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.uci.dao.service.HealthService; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.info.License; + @Configuration public class AppConfigInbound { - @Bean - public HealthService healthService() { - return new HealthService(); - } + @Bean + public HealthService healthService() { + return new HealthService(); + } + + @Bean + public OpenAPI customOpenAPI(@Value("${application-title}") String appTitle, + @Value("${application-version}") String appVersion) { + return new OpenAPI().info(new Info().title(appTitle).version(appVersion) + .description(appTitle + " Api Documentation").termsOfService("http://swagger.io/terms/") + .license(new License().name("Apache 2.0").url("http://springdoc.org"))); + } } diff --git a/src/main/java/com/uci/inbound/api/response/examples/ComponentHealthApiExample.java b/src/main/java/com/uci/inbound/api/response/examples/ComponentHealthApiExample.java new file mode 100644 index 0000000..da05cb0 --- /dev/null +++ b/src/main/java/com/uci/inbound/api/response/examples/ComponentHealthApiExample.java @@ -0,0 +1,8 @@ +package com.uci.inbound.api.response.examples; + +import com.uci.inbound.api.response.examples.params.ComponentHealthApiResultParameter; +import com.uci.inbound.api.response.examples.params.HealthApiResultParameter; + +public class ComponentHealthApiExample extends HealthApiExample { + public ComponentHealthApiResultParameter result; +} diff --git a/src/main/java/com/uci/inbound/api/response/examples/HealthApiExample.java b/src/main/java/com/uci/inbound/api/response/examples/HealthApiExample.java new file mode 100644 index 0000000..1e35117 --- /dev/null +++ b/src/main/java/com/uci/inbound/api/response/examples/HealthApiExample.java @@ -0,0 +1,22 @@ +package com.uci.inbound.api.response.examples; + +import com.uci.inbound.api.response.examples.params.HealthApiParamsParameter; +import com.uci.inbound.api.response.examples.params.HealthApiResultParameter; + +import io.swagger.v3.oas.annotations.media.Schema; + +public class HealthApiExample { + @Schema(example = "api.content.health") + public String id; + + @Schema(example = "3.0") + public String ver; + + @Schema(example = "2021-09-01T11:14:50Z") + public String ts; + + public HealthApiParamsParameter params; + + @Schema(example = "OK") + public String responseCode; +} diff --git a/src/main/java/com/uci/inbound/api/response/examples/SystemHealthApiExample.java b/src/main/java/com/uci/inbound/api/response/examples/SystemHealthApiExample.java new file mode 100644 index 0000000..081957d --- /dev/null +++ b/src/main/java/com/uci/inbound/api/response/examples/SystemHealthApiExample.java @@ -0,0 +1,7 @@ +package com.uci.inbound.api.response.examples; + +import com.uci.inbound.api.response.examples.params.HealthApiResultParameter; + +public class SystemHealthApiExample extends HealthApiExample{ + public HealthApiResultParameter result; +} diff --git a/src/main/java/com/uci/inbound/api/response/examples/params/ComponentHealthApiResultParameter.java b/src/main/java/com/uci/inbound/api/response/examples/params/ComponentHealthApiResultParameter.java new file mode 100644 index 0000000..82dc0df --- /dev/null +++ b/src/main/java/com/uci/inbound/api/response/examples/params/ComponentHealthApiResultParameter.java @@ -0,0 +1,10 @@ +package com.uci.inbound.api.response.examples.params; + +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; + +public class ComponentHealthApiResultParameter { + @Schema(example = "true") + public Boolean healthy; +} diff --git a/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiChecksParameter.java b/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiChecksParameter.java new file mode 100644 index 0000000..a744f1c --- /dev/null +++ b/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiChecksParameter.java @@ -0,0 +1,11 @@ +package com.uci.inbound.api.response.examples.params; + +import io.swagger.v3.oas.annotations.media.Schema; + +public class HealthApiChecksParameter { + @Schema(example = "Cassandra") + public String name; + + @Schema(example = "true") + public Boolean healthy; +} diff --git a/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiParamsParameter.java b/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiParamsParameter.java new file mode 100644 index 0000000..23338d2 --- /dev/null +++ b/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiParamsParameter.java @@ -0,0 +1,20 @@ +package com.uci.inbound.api.response.examples.params; + +import io.swagger.v3.oas.annotations.media.Schema; + +public class HealthApiParamsParameter { + @Schema(example = "859fee0c-94d6-4a0d-b786-2025d763b78a") + public String resmsgid; + + @Schema(example = "null") + public String msgid; + + @Schema(example = "null") + public String err; + + @Schema(example = "Successful") + public String status; + + @Schema(example = "null") + public String errmsg; +} diff --git a/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiResultParameter.java b/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiResultParameter.java new file mode 100644 index 0000000..e989b07 --- /dev/null +++ b/src/main/java/com/uci/inbound/api/response/examples/params/HealthApiResultParameter.java @@ -0,0 +1,12 @@ +package com.uci.inbound.api.response.examples.params; + +import java.util.List; + +import io.swagger.v3.oas.annotations.media.Schema; + +public class HealthApiResultParameter { + public List checks; + + @Schema(example = "true") + public Boolean healthy; +} diff --git a/src/main/java/com/uci/inbound/cdac/CDACConverter.java b/src/main/java/com/uci/inbound/cdac/CDACConverter.java index 29da7e6..b07bcb5 100644 --- a/src/main/java/com/uci/inbound/cdac/CDACConverter.java +++ b/src/main/java/com/uci/inbound/cdac/CDACConverter.java @@ -6,6 +6,8 @@ import com.uci.inbound.utils.XMsgProcessingUtil; import com.uci.dao.repository.XMessageRepository; import com.uci.utils.kafka.SimpleProducer; + +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -42,7 +44,8 @@ public class CDACConverter { @Autowired public XMessageRepository xmsgRepo; - + + @Operation(hidden = true) @RequestMapping(value = "/sms/bulk/", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public void cdacBulk(@Valid CommonMessage message) throws JsonProcessingException { @@ -56,6 +59,7 @@ public void cdacBulk(@Valid CommonMessage message) throws JsonProcessingExceptio .build().process(); } + @Operation(hidden = true) @RequestMapping(value = "/sms/single/", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public void cdacSingle(@Valid CommonMessage message) throws JsonProcessingException { diff --git a/src/main/java/com/uci/inbound/diksha/web/DikshaWebController.java b/src/main/java/com/uci/inbound/diksha/web/DikshaWebController.java index e6db773..8845af7 100644 --- a/src/main/java/com/uci/inbound/diksha/web/DikshaWebController.java +++ b/src/main/java/com/uci/inbound/diksha/web/DikshaWebController.java @@ -3,10 +3,17 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.uci.adapter.sunbird.web.SunbirdWebPortalAdapter; import com.uci.adapter.sunbird.web.inbound.DikshaWebMessageFormat; +import com.uci.inbound.api.response.examples.ComponentHealthApiExample; import com.uci.inbound.utils.XMsgProcessingUtil; import com.uci.dao.repository.XMessageRepository; import com.uci.utils.BotService; import com.uci.utils.kafka.SimpleProducer; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -23,39 +30,35 @@ @RequestMapping(value = "/diksha") public class DikshaWebController { - @Value("${inboundProcessed}") - private String inboundProcessed; + @Value("${inboundProcessed}") + private String inboundProcessed; - @Value("${inbound-error}") - private String inboundError; + @Value("${inbound-error}") + private String inboundError; - private SunbirdWebPortalAdapter sunbirdWebPortalAdapter; + private SunbirdWebPortalAdapter sunbirdWebPortalAdapter; - @Autowired - public SimpleProducer kafkaProducer; + @Autowired + public SimpleProducer kafkaProducer; - @Autowired - public XMessageRepository xmsgRepo; + @Autowired + public XMessageRepository xmsgRepo; - @Autowired - public BotService botService; + @Autowired + public BotService botService; - @RequestMapping(value = "/web", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) - public void dikshaWeb(@RequestBody DikshaWebMessageFormat message) throws JsonProcessingException, JAXBException { + @Operation(hidden = true, summary = "Send message to kafka topic via sunbird service", description = "This API is used to get send message to inbound kafka topic received from sunbird service.") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { + @Content }) }) + @RequestMapping(value = "/web", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) + public void dikshaWeb(@RequestBody DikshaWebMessageFormat message) throws JsonProcessingException, JAXBException { - System.out.println(message.toString()); + System.out.println(message.toString()); - sunbirdWebPortalAdapter = SunbirdWebPortalAdapter.builder() - .build(); + sunbirdWebPortalAdapter = SunbirdWebPortalAdapter.builder().build(); - XMsgProcessingUtil.builder() - .adapter(sunbirdWebPortalAdapter) - .xMsgRepo(xmsgRepo) - .inboundMessage(message.getMessages()[0]) - .topicFailure(inboundError) - .topicSuccess(inboundProcessed) - .kafkaProducer(kafkaProducer) - .build() - .process(); - } + XMsgProcessingUtil.builder().adapter(sunbirdWebPortalAdapter).xMsgRepo(xmsgRepo) + .inboundMessage(message.getMessages()[0]).topicFailure(inboundError).topicSuccess(inboundProcessed) + .kafkaProducer(kafkaProducer).build().process(); + } } diff --git a/src/main/java/com/uci/inbound/health/HealthController.java b/src/main/java/com/uci/inbound/health/HealthController.java index b490b83..e14a6e4 100644 --- a/src/main/java/com/uci/inbound/health/HealthController.java +++ b/src/main/java/com/uci/inbound/health/HealthController.java @@ -5,7 +5,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.uci.dao.service.HealthService; +import com.uci.inbound.api.response.examples.HealthApiExample; +import com.uci.inbound.api.response.examples.SystemHealthApiExample; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import java.io.IOException; @@ -20,24 +28,30 @@ @Slf4j @RestController +@Tag(name = "System Health Apis") public class HealthController { - + @Autowired private HealthService healthService; - - @RequestMapping(value = "/health", method = RequestMethod.GET, produces = { "application/json", "text/json" }) - public ResponseEntity statusCheck() throws JsonProcessingException, IOException { - ObjectMapper mapper = new ObjectMapper(); - /* Current Date Time */ - LocalDateTime localNow = LocalDateTime.now(); - DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"); - String dateString = fmt.format(localNow).toString(); - - JsonNode jsonNode = mapper.readTree("{\"id\":\"api.content.health\",\"ver\":\"3.0\",\"ts\":\"2021-06-26T22:47:05Z+05:30\",\"params\":{\"resmsgid\":\"859fee0c-94d6-4a0d-b786-2025d763b78a\",\"msgid\":null,\"err\":null,\"status\":\"successful\",\"errmsg\":null},\"responseCode\":\"OK\",\"result\":{\"checks\":[{\"name\":\"redis cache\",\"healthy\":true},{\"name\":\"graph db\",\"healthy\":true},{\"name\":\"cassandra db\",\"healthy\":true}],\"healthy\":true}}"); - - ((ObjectNode) jsonNode).put("ts", dateString); - ((ObjectNode) jsonNode).put("result", healthService.getAllHealthNode()); - - return ResponseEntity.ok(jsonNode); - } + + @Operation(summary = "Get System Health", description = "This API is used to get system health. It included health of two components.\n" + + "- Kafka\n" + "- Cassandra") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = SystemHealthApiExample.class)) }) }) + @RequestMapping(value = "/health", method = RequestMethod.GET, produces = { "application/json", "text/json" }) + public ResponseEntity statusCheck() throws JsonProcessingException, IOException { + ObjectMapper mapper = new ObjectMapper(); + /* Current Date Time */ + LocalDateTime localNow = LocalDateTime.now(); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'"); + String dateString = fmt.format(localNow).toString(); + + JsonNode jsonNode = mapper.readTree( + "{\"id\":\"api.content.health\",\"ver\":\"3.0\",\"ts\":\"2021-06-26T22:47:05Z+05:30\",\"params\":{\"resmsgid\":\"859fee0c-94d6-4a0d-b786-2025d763b78a\",\"msgid\":null,\"err\":null,\"status\":\"successful\",\"errmsg\":null},\"responseCode\":\"OK\",\"result\":{\"checks\":[{\"name\":\"redis cache\",\"healthy\":true},{\"name\":\"graph db\",\"healthy\":true},{\"name\":\"cassandra db\",\"healthy\":true}],\"healthy\":true}}"); + + ((ObjectNode) jsonNode).put("ts", dateString); + ((ObjectNode) jsonNode).put("result", healthService.getAllHealthNode()); + + return ResponseEntity.ok(jsonNode); + } } diff --git a/src/main/java/com/uci/inbound/health/ServiceStatusController.java b/src/main/java/com/uci/inbound/health/ServiceStatusController.java index 9a80d13..9272b4c 100644 --- a/src/main/java/com/uci/inbound/health/ServiceStatusController.java +++ b/src/main/java/com/uci/inbound/health/ServiceStatusController.java @@ -9,8 +9,16 @@ import com.uci.dao.repository.XMessageRepository; import com.uci.utils.BotService; import com.uci.dao.service.HealthService; +import com.uci.inbound.api.response.examples.ComponentHealthApiExample; +import com.uci.inbound.api.response.examples.HealthApiExample; import com.uci.utils.kafka.KafkaConfig; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -31,44 +39,57 @@ @Slf4j @RestController @RequestMapping(value = "/service") +@Tag(name = "Services Health Api") public class ServiceStatusController { - @Autowired + @Autowired private HealthService healthService; - - @RequestMapping(value = "/health/cassandra", method = RequestMethod.GET, produces = { "application/json", "text/json" }) - public ResponseEntity cassandraStatusCheck() throws IOException, JsonProcessingException { - JsonNode jsonNode = getResponseJsonNode(); - ((ObjectNode) jsonNode).put("result", healthService.getCassandraHealthNode()); - - return ResponseEntity.ok(jsonNode); - } - - @RequestMapping(value = "/health/kafka", method = RequestMethod.GET, produces = { "application/json", "text/json" }) - public ResponseEntity kafkaStatusCheck() throws IOException, JsonProcessingException { - JsonNode jsonNode = getResponseJsonNode(); - ((ObjectNode) jsonNode).put("result", healthService.getKafkaHealthNode()); - - return ResponseEntity.ok(jsonNode); - } - - @RequestMapping(value = "/health/campaign", method = RequestMethod.GET, produces = { "application/json", "text/json" }) - public ResponseEntity campaignUrlStatusCheck() throws JsonProcessingException, IOException { - JsonNode jsonNode = getResponseJsonNode(); - ((ObjectNode) jsonNode).put("result", healthService.getCampaignUrlHealthNode()); - - return ResponseEntity.ok(jsonNode); - } - - /** - * Returns json node for service response - * - * @return JsonNode - * @throws JsonMappingException - * @throws JsonProcessingException - */ - private JsonNode getResponseJsonNode() throws JsonMappingException, JsonProcessingException { - ObjectMapper mapper = new ObjectMapper(); - JsonNode jsonNode = mapper.readTree("{\"id\":\"api.content.service.health\",\"ver\":\"3.0\",\"ts\":null,\"params\":{\"resmsgid\":null,\"msgid\":null,\"err\":null,\"status\":\"successful\",\"errmsg\":null},\"responseCode\":\"OK\",\"result\":{\"healthy\":false}}"); - return jsonNode; - } + + @Operation(summary = "Get Cassandra Health", description = "This API is used to get cassandra health status") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = ComponentHealthApiExample.class)) }) }) + @RequestMapping(value = "/health/cassandra", method = RequestMethod.GET, produces = { "application/json", + "text/json" }) + public ResponseEntity cassandraStatusCheck() throws IOException, JsonProcessingException { + JsonNode jsonNode = getResponseJsonNode(); + ((ObjectNode) jsonNode).put("result", healthService.getCassandraHealthNode()); + + return ResponseEntity.ok(jsonNode); + } + + @Operation(summary = "Get Kafka Health", description = "This API is used to get kafka health status") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = ComponentHealthApiExample.class)) }) }) + @RequestMapping(value = "/health/kafka", method = RequestMethod.GET, produces = { "application/json", "text/json" }) + public ResponseEntity kafkaStatusCheck() throws IOException, JsonProcessingException { + JsonNode jsonNode = getResponseJsonNode(); + ((ObjectNode) jsonNode).put("result", healthService.getKafkaHealthNode()); + + return ResponseEntity.ok(jsonNode); + } + + @Operation(summary = "Get Campaign Health", description = "This API is used to get campaign health status") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { + @Content(mediaType = "application/json", schema = @Schema(implementation = ComponentHealthApiExample.class)) }) }) + @RequestMapping(value = "/health/campaign", method = RequestMethod.GET, produces = { "application/json", + "text/json" }) + public ResponseEntity campaignUrlStatusCheck() throws JsonProcessingException, IOException { + JsonNode jsonNode = getResponseJsonNode(); + ((ObjectNode) jsonNode).put("result", healthService.getCampaignUrlHealthNode()); + + return ResponseEntity.ok(jsonNode); + } + + /** + * Returns json node for service response + * + * @return JsonNode + * @throws JsonMappingException + * @throws JsonProcessingException + */ + private JsonNode getResponseJsonNode() throws JsonMappingException, JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + JsonNode jsonNode = mapper.readTree( + "{\"id\":\"api.content.service.health\",\"ver\":\"3.0\",\"ts\":null,\"params\":{\"resmsgid\":null,\"msgid\":null,\"err\":null,\"status\":\"successful\",\"errmsg\":null},\"responseCode\":\"OK\",\"result\":{\"healthy\":false}}"); + return jsonNode; + } } diff --git a/src/main/java/com/uci/inbound/incoming/Campaign.java b/src/main/java/com/uci/inbound/incoming/Campaign.java index 3f759e9..7f98467 100644 --- a/src/main/java/com/uci/inbound/incoming/Campaign.java +++ b/src/main/java/com/uci/inbound/incoming/Campaign.java @@ -6,6 +6,12 @@ import com.uci.adapter.cdac.TrackDetails; import com.uci.adapter.provider.factory.ProviderFactory; import com.uci.utils.kafka.SimpleProducer; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -17,6 +23,7 @@ @CrossOrigin @RestController @RequestMapping(value = "/campaign") +@Tag(name = "Campaign Apis") public class Campaign { @Value("${campaign}") private String campaign; @@ -27,25 +34,32 @@ public class Campaign { @Autowired private ProviderFactory factoryProvider; - @RequestMapping(value = "/start", method = RequestMethod.GET) + @Operation(summary = "Start Campaign", description = "This API is used to start the campaign kafka topic." + + "- The fields marked with an asterisk (*) are mandatory. They cannot be null or empty.") + @RequestMapping(value = "/start", method = RequestMethod.GET) public void startCampaign(@RequestParam("campaignId") String campaignId) throws JsonProcessingException, JAXBException { kafkaProducer.send(campaign, campaignId); return; } - @RequestMapping(value = "/pause", method = RequestMethod.GET) + @Operation(summary = "Pause Campaign", description = "This API is used to pause the campaign kafka topic.") + @RequestMapping(value = "/pause", method = RequestMethod.GET) public void pauseCampaign(@RequestParam("campaignId") String campaignId) throws JsonProcessingException, JAXBException { kafkaProducer.send(campaign, campaignId); return; } - @RequestMapping(value = "/resume", method = RequestMethod.GET) + @Operation(summary = "Resume Campaign", description = "This API is used to start campaign kafka topic.") + @RequestMapping(value = "/resume", method = RequestMethod.GET) public void resumeCampaign(@RequestParam("campaignId") String campaignId) throws JsonProcessingException, JAXBException { kafkaProducer.send(campaign, campaignId); return; } - @RequestMapping(value = "/status/cdac/bulk", method = RequestMethod.GET) + @Operation(hidden = true, summary = "Get Campaign Status", description = "This API is used to get campaign status from CDAC Sms Adapter.") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { + @Content }) }) + @RequestMapping(value = "/status/cdac/bulk", method = RequestMethod.GET) public TrackDetails getCampaignStatus(@RequestParam("campaignId") String campaignId) { CdacBulkSmsAdapter iprovider = (CdacBulkSmsAdapter) factoryProvider.getProvider("cdac", "SMS"); try { diff --git a/src/main/java/com/uci/inbound/incoming/GupShupOptIn.java b/src/main/java/com/uci/inbound/incoming/GupShupOptIn.java index 5c8839a..da3cc05 100644 --- a/src/main/java/com/uci/inbound/incoming/GupShupOptIn.java +++ b/src/main/java/com/uci/inbound/incoming/GupShupOptIn.java @@ -1,6 +1,8 @@ package com.uci.inbound.incoming; import com.uci.adapter.gs.whatsapp.GSWhatsAppMessage; + +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -13,6 +15,8 @@ @RestController @RequestMapping(value = "/whatsapp") public class GupShupOptIn { + + @Operation(hidden = true) @RequestMapping(value = "/opt-in", method = RequestMethod.POST) public void gupShupWhatsApp(@Valid @RequestBody GSWhatsAppMessage message) throws Exception { diff --git a/src/main/java/com/uci/inbound/incoming/GupShupWhatsappConverter.java b/src/main/java/com/uci/inbound/incoming/GupShupWhatsappConverter.java index 3a454e7..a3cdaae 100644 --- a/src/main/java/com/uci/inbound/incoming/GupShupWhatsappConverter.java +++ b/src/main/java/com/uci/inbound/incoming/GupShupWhatsappConverter.java @@ -4,10 +4,23 @@ import javax.xml.bind.JAXBException; import com.uci.adapter.gs.whatsapp.GupShupWhatsappAdapter; +import com.uci.adapter.netcore.whatsapp.inbound.NetcoreMessageFormat; import com.uci.dao.repository.XMessageRepository; import com.uci.utils.BotService; import com.uci.inbound.utils.XMsgProcessingUtil; import com.uci.utils.kafka.SimpleProducer; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; @@ -23,6 +36,7 @@ @Slf4j @RestController @RequestMapping(value = "/gupshup") +@Tag(name = "Gupshup Apis") public class GupShupWhatsappConverter { @Value("${inboundProcessed}") @@ -45,7 +59,44 @@ public class GupShupWhatsappConverter { @Autowired public BotService botService; - @RequestMapping(value = "/whatsApp", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @Operation(summary = "Send message to kafka topic via gupshup whatsapp service", description = "This API is used to get send message to inbound kafka topic received from gupshup whatsapp service.") +// @Parameters(value = { +// @Parameter(name = "waNumber", examples={ @ExampleObject(name = "Text Message", description = "This is WhatsApp Business number on which the " +// + "customer has sent a message", value = "919560222091")}), +// @Parameter(name = "mobile", examples={ @ExampleObject(name = "Text Message", description = "The phone number of the customer who has sent " +// + "the message", value = "919004371797")}), +// @Parameter(name = "replyId", examples={ @ExampleObject(name = "Text Message", description = "The unique system identifier for the original message sent by the business to the customer, on " +// + "which the customer has replied (swipe left action on" +// + "WhatsApp to reply to a specific message). This is the" +// + "transaction ID of the original message.", value = "3900363981641897487")}), +// @Parameter(name = "messageId", examples={ @ExampleObject(name = "Text Message", description = "The unique identifier for the original message sent " +// + "by the business to the customer, on which the" +// + "customer has replied (swipe left action on WhatsApp" +// + "to reply to a specific message). This is the message" +// + "ID that can be a custom value specified in the Send" +// + "Message API request.", value = "custom Message ID")}), +// @Parameter(name = "text", examples={ @ExampleObject(name = "Text Message", description = "The text message sent by the user", value = "Hi UCI")}), +// @Parameter(name = "type", examples={ @ExampleObject(name = "Text Message", description = "The name of the Gupshup app to which the" +// + "customer has sent a message on WhatsApp\n." +// + "Must be one of : text, image, document, voice, audio, video," +// + "location, contacts", value = "text")}), +// @Parameter(name = "timestamp", examples={ @ExampleObject(name = "Text Message", description = "The time in unix timestamp in milliseconds when the" +// + "message sent by the customer was received by" +// + "Gupshup", value = "1564471290000")}) +// }) +// @RequestBody(content = @Content( +// mediaType = "application/x-www-form-urlencoded", +// schema = @Schema(implementation = GSWhatsAppMessage.class), +// examples = { +// @ExampleObject( +// name = "waNumber", description = "Request body for text messages", +// value = "test") +// } +// ) +// ) + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { + @Content }) }) + @RequestMapping(value = "/whatsApp", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public void gupshupWhatsApp(@Valid GSWhatsAppMessage message) throws JsonProcessingException, JAXBException { gupShupWhatsappAdapter = GupShupWhatsappAdapter.builder() diff --git a/src/main/java/com/uci/inbound/incoming/InternalBot.java b/src/main/java/com/uci/inbound/incoming/InternalBot.java index 9f2c45a..10b9407 100644 --- a/src/main/java/com/uci/inbound/incoming/InternalBot.java +++ b/src/main/java/com/uci/inbound/incoming/InternalBot.java @@ -4,6 +4,7 @@ import com.uci.adapter.provider.factory.ProviderFactory; import com.uci.utils.kafka.SimpleProducer; import io.fusionauth.domain.User; +import io.swagger.v3.oas.annotations.Operation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -30,6 +31,7 @@ public class InternalBot { @Autowired private ProviderFactory factoryProvider; + @Operation(hidden = true) @RequestMapping(value = "/delete-leave", method = RequestMethod.GET) public ResponseEntity deleteLeave( @RequestParam(value = "userEmail", required = false) String userEmail, @@ -40,6 +42,7 @@ public ResponseEntity deleteLeave( return restTemplate.getForEntity(url, User.class); } + @Operation(hidden = true) @RequestMapping(value = "/approve-leave", method = RequestMethod.GET) public ResponseEntity approveLeave( @RequestParam(value = "userEmail", required = false) String userEmail, @@ -50,6 +53,7 @@ public ResponseEntity approveLeave( return restTemplate.getForEntity(url, User.class); } + @Operation(hidden = true) @RequestMapping(value = "/reject-leave", method = RequestMethod.GET) public ResponseEntity rejectLeave( @RequestParam(value = "userEmail", required = false) String userEmail, diff --git a/src/main/java/com/uci/inbound/netcore/NetcoreWhatsappConverter.java b/src/main/java/com/uci/inbound/netcore/NetcoreWhatsappConverter.java index ba5a200..744addf 100644 --- a/src/main/java/com/uci/inbound/netcore/NetcoreWhatsappConverter.java +++ b/src/main/java/com/uci/inbound/netcore/NetcoreWhatsappConverter.java @@ -2,10 +2,21 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.uci.adapter.netcore.whatsapp.inbound.NetcoreMessageFormat; +import com.uci.adapter.gs.whatsapp.GSWhatsAppMessage; import com.uci.adapter.netcore.whatsapp.NetcoreWhatsappAdapter; import com.uci.inbound.utils.XMsgProcessingUtil; import com.uci.dao.repository.XMessageRepository; import com.uci.utils.kafka.SimpleProducer; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Parameters; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.ExampleObject; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import com.uci.utils.BotService; import org.springframework.beans.factory.annotation.Autowired; @@ -16,51 +27,73 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; + import javax.xml.bind.JAXBException; @Slf4j @RestController @RequestMapping(value = "/netcore") +@Tag(name = "Netcore Apis") public class NetcoreWhatsappConverter { - @Value("${inboundProcessed}") - private String inboundProcessed; - - @Value("${gupshup-opted-out}") - private String optedOut; + @Value("${inboundProcessed}") + private String inboundProcessed; - @Value("${inbound-error}") - private String inboundError; + @Value("${gupshup-opted-out}") + private String optedOut; - private NetcoreWhatsappAdapter netcoreWhatsappAdapter; + @Value("${inbound-error}") + private String inboundError; - @Autowired - public SimpleProducer kafkaProducer; + private NetcoreWhatsappAdapter netcoreWhatsappAdapter; - @Autowired - public XMessageRepository xmsgRepo; + @Autowired + public SimpleProducer kafkaProducer; - @Autowired - public BotService botService; + @Autowired + public XMessageRepository xmsgRepo; - @RequestMapping(value = "/whatsApp", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) - public void netcoreWhatsApp(@RequestBody NetcoreMessageFormat message) throws JsonProcessingException, JAXBException { + @Autowired + public BotService botService; + + @Operation(summary = "Send message to kafka topic via netcore whatsapp service", description = "This API is used to get send message to inbound kafka topic received from netcore whatsapp service.") + @io.swagger.v3.oas.annotations.parameters.RequestBody( + content = @Content( + schema = @Schema(implementation = NetcoreMessageFormat.class), + examples = { + @ExampleObject( + name = "Text Message", description = "Request body for text messages", + value = "{\n" + + " \"messages\": [\n" + + " {\n" + + " \"message_id\": \"ABEGkZlgQyWAAgo-sDVSUOa9jH0z\",\n" + + " \"from\": \"919960432580\",\n" + + " \"received_at\": \"1567090835\",\n" + + " \"context\": {\n" + + " \"ncmessage_id\": null,\n" + + " \"message_id\": null\n" + + " },\n" + + " \"message_type\": \"TEXT\",\n" + + " \"text_type\": {\n" + + " \"text\": \"Hi UCI\"\n" + + " }\n" + + " }\n" + + " ]\n" + + "}") +// , @ExampleObject(name = "test2", value = "test2") + })) + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "OK!", content = { @Content }) }) + @RequestMapping(value = "/whatsApp", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) + public void netcoreWhatsApp(@RequestBody NetcoreMessageFormat message) + throws JsonProcessingException, JAXBException { - System.out.println(message.toString()); + System.out.println(message.toString()); - netcoreWhatsappAdapter = NetcoreWhatsappAdapter.builder() - .botservice(botService) - .build(); + netcoreWhatsappAdapter = NetcoreWhatsappAdapter.builder().botservice(botService).build(); - XMsgProcessingUtil.builder() - .adapter(netcoreWhatsappAdapter) - .xMsgRepo(xmsgRepo) - .inboundMessage(message.getMessages()[0]) - .topicFailure(inboundError) - .topicSuccess(inboundProcessed) - .kafkaProducer(kafkaProducer) - .botService(botService) - .build() - .process(); - } + XMsgProcessingUtil.builder().adapter(netcoreWhatsappAdapter).xMsgRepo(xmsgRepo) + .inboundMessage(message.getMessages()[0]).topicFailure(inboundError).topicSuccess(inboundProcessed) + .kafkaProducer(kafkaProducer).botService(botService).build().process(); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 965059e..654f6fc 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -29,5 +29,8 @@ campaign.url = ${CAMPAIGN_URL} campaign.admin.token = ${CAMPAIGN_ADMIN_TOKEN} +application-title=UCI Inbound +application-version=1.0 +