diff --git a/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/config/HelpConfig.java b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/config/HelpConfig.java new file mode 100644 index 000000000..fb2804506 --- /dev/null +++ b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/config/HelpConfig.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright 2014 CapitalOne, LLC. + * Further development Copyright 2022 Sapient Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +package com.publicissapient.kpidashboard.apis.appsetting.config; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Configuration properties for help and documentation resources. + * + * @author aksshriv1 + */ +@Component +@ConfigurationProperties(prefix = "help") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class HelpConfig { + + private String productDocumentationUrl; + private String apiDocumentationUrl; + private String videoTutorialsUrl; + private String raiseTicketUrl; + private String supportChannelUrl; +} diff --git a/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/config/PEBConfig.java b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/config/PEBConfig.java new file mode 100644 index 000000000..a1379ff69 --- /dev/null +++ b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/config/PEBConfig.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright 2014 CapitalOne, LLC. + * Further development Copyright 2022 Sapient Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +package com.publicissapient.kpidashboard.apis.appsetting.config; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Configuration properties for Potential Economic Benefits Calculator. + * + * @author aksshriv1 + */ +@Component +@ConfigurationProperties(prefix = "peb") +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class PEBConfig { + + private Integer totalDevelopers; + private Double avgCostPerDeveloper; + private String timeDuration; +} diff --git a/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/rest/HelpAndSupportController.java b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/rest/HelpAndSupportController.java new file mode 100644 index 000000000..85a9b3702 --- /dev/null +++ b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/rest/HelpAndSupportController.java @@ -0,0 +1,223 @@ +/******************************************************************************* + * Copyright 2014 CapitalOne, LLC. + * Further development Copyright 2022 Sapient Corporation. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ + +package com.publicissapient.kpidashboard.apis.appsetting.rest; + +import com.publicissapient.kpidashboard.apis.appsetting.config.HelpConfig; +import com.publicissapient.kpidashboard.apis.appsetting.config.PEBConfig; +import com.publicissapient.kpidashboard.apis.model.ServiceResponse; +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 org.springframework.beans.factory.annotation.Autowired; +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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.net.URI; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * REST controller for managing help and documentation resources. + * Provides endpoints to retrieve help configuration and redirect to external documentation URLs. + * + * @author aksshriv1 + */ +@RestController +@RequestMapping("/help") +@Tag(name = "Help", description = "Endpoints for managing support and documentation resources") +@Slf4j +public class HelpAndSupportController { + + @Autowired + private HelpConfig helpConfig; + + public void setHelpConfig(HelpConfig helpConfig) { + this.helpConfig = helpConfig; + } + + /** + * Retrieves all configured help resource URLs. + * Returns a map containing URLs for product documentation, API documentation, + * video tutorials, ticket raising, and support channels. + * + * @return ResponseEntity containing a map of help resource names to their URLs + */ + @GetMapping(value = "/config", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation( + summary = "Get Help Configuration", + description = "Retrieves all configured help resource URLs including documentation, tutorials, and support channels") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved help configuration", + content = { + @Content( + mediaType = "application/json", + schema = @Schema(implementation = ServiceResponse.class)) + }) + }) + public ResponseEntity getHelpConfig() { + log.info("Fetching help configuration"); + Map resourceLinks = new LinkedHashMap<>(); + resourceLinks.put("productDocumentation", helpConfig.getProductDocumentationUrl() != null ? helpConfig.getProductDocumentationUrl() : ""); + resourceLinks.put("apiDocumentation", helpConfig.getApiDocumentationUrl() != null ? helpConfig.getApiDocumentationUrl() : ""); + resourceLinks.put("videoTutorials", helpConfig.getVideoTutorialsUrl() != null ? helpConfig.getVideoTutorialsUrl() : ""); + resourceLinks.put("raiseTicket", helpConfig.getRaiseTicketUrl() != null ? helpConfig.getRaiseTicketUrl() : ""); + resourceLinks.put("supportChannel", helpConfig.getSupportChannelUrl() != null ? helpConfig.getSupportChannelUrl() : ""); + log.info("Help configuration retrieved successfully"); + return ResponseEntity.ok(new ServiceResponse(true, "Help and Support configuration retrieved successfully", resourceLinks)); + } + + /** + * Redirects to the API documentation URL. + * + * @return ResponseEntity with HTTP 302 redirect or 404 if URL is not configured + */ + @GetMapping("/api-documentation") + @Operation( + summary = "Redirect to API Documentation", + description = "Redirects to the configured API documentation URL") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "302", + description = "Successfully redirected to API documentation"), + @ApiResponse( + responseCode = "404", + description = "API documentation URL is not configured") + }) + public ResponseEntity redirectToApiDocumentation() { + log.info("Redirecting to API documentation"); + return redirectToUrl(helpConfig.getApiDocumentationUrl(), "API documentation"); + } + + /** + * Redirects to the product documentation URL. + * + * @return ResponseEntity with HTTP 302 redirect or 404 if URL is not configured + */ + @GetMapping("/product-documentation") + @Operation( + summary = "Redirect to Product Documentation", + description = "Redirects to the configured product documentation URL") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "302", + description = "Successfully redirected to product documentation"), + @ApiResponse( + responseCode = "404", + description = "Product documentation URL is not configured") + }) + public ResponseEntity redirectToProductDocumentation() { + log.info("Redirecting to product documentation"); + return redirectToUrl(helpConfig.getProductDocumentationUrl(), "Product documentation"); + } + + /** + * Redirects to the video tutorials URL. + * + * @return ResponseEntity with HTTP 302 redirect or 404 if URL is not configured + */ + @GetMapping("/video-tutorials") + @Operation( + summary = "Redirect to Video Tutorials", + description = "Redirects to the configured video tutorials URL") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "302", + description = "Successfully redirected to video tutorials"), + @ApiResponse( + responseCode = "404", + description = "Video tutorials URL is not configured") + }) + public ResponseEntity redirectToVideoTutorials() { + log.info("Redirecting to video tutorials"); + return redirectToUrl(helpConfig.getVideoTutorialsUrl(), "Video tutorials"); + } + + /** + * Redirects to the ticket raising URL. + * + * @return ResponseEntity with HTTP 302 redirect or 404 if URL is not configured + */ + @GetMapping("/raise-ticket") + @Operation( + summary = "Redirect to Raise Ticket", + description = "Redirects to the configured ticket raising URL") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "302", + description = "Successfully redirected to ticket raising page"), + @ApiResponse( + responseCode = "404", + description = "Ticket raising URL is not configured") + }) + public ResponseEntity redirectToRaiseTicket() { + log.info("Redirecting to raise ticket"); + return redirectToUrl(helpConfig.getRaiseTicketUrl(), "Raise ticket"); + } + + /** + * Redirects to the support channel URL. + * + * @return ResponseEntity with HTTP 302 redirect or 404 if URL is not configured + */ + @GetMapping("/support-channel") + @Operation( + summary = "Redirect to Support Channel", + description = "Redirects to the configured support channel URL") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "302", + description = "Successfully redirected to support channel"), + @ApiResponse( + responseCode = "404", + description = "Support channel URL is not configured") + }) + public ResponseEntity redirectToSupportChannel() { + log.info("Redirecting to support channel"); + return redirectToUrl(helpConfig.getSupportChannelUrl(), "Support channel"); + } + + /** + * Helper method to perform URL redirection. + * Validates the URL and returns appropriate HTTP status. + * + * @param url the URL to redirect to + * @param resourceName the name of the resource being redirected to + * @return ResponseEntity with HTTP 302 (Found) for valid URLs or 404 (Not Found) for invalid/empty URLs + */ + private ResponseEntity redirectToUrl(String url, String resourceName) { + if (url == null || url.trim().isEmpty()) { + log.warn("{} URL is not configured", resourceName); + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } + log.info("Redirecting to {} URL: {}", resourceName, url); + return ResponseEntity.status(HttpStatus.FOUND).location(URI.create(url)).build(); + } +} diff --git a/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/rest/PEBConfigController.java b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/rest/PEBConfigController.java new file mode 100644 index 000000000..b364e3ef0 --- /dev/null +++ b/src/main/java/com/publicissapient/kpidashboard/apis/appsetting/rest/PEBConfigController.java @@ -0,0 +1,64 @@ +package com.publicissapient.kpidashboard.apis.appsetting.rest; + +import com.publicissapient.kpidashboard.apis.appsetting.config.PEBConfig; +import com.publicissapient.kpidashboard.apis.model.ServiceResponse; +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 org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.LinkedHashMap; +import java.util.Map; + +@RestController +@RequestMapping("/peb") +@Tag(name = "PotentialEconomicBenefit", description = "Endpoints for PEB Calculator Configuration") +@Slf4j +public class PEBConfigController { + + @Autowired + private PEBConfig pebConfig; + + public void setPebConfig(PEBConfig pebConfig) { + this.pebConfig = pebConfig; + } + + /** + * Retrieves Potential Economic Benefits configuration. + * + * @return ResponseEntity containing PEB configuration parameters + */ + @GetMapping(value = "/configs", produces = MediaType.APPLICATION_JSON_VALUE) + @Operation( + summary = "Get Economic Benefits Configuration", + description = "Retrieves Potential Economic Benefits calculator configuration parameters") + @ApiResponses( + value = { + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved PEB configuration", + content = { + @Content( + mediaType = "application/json", + schema = @Schema(implementation = ServiceResponse.class)) + }) + }) + public ResponseEntity getEconomicBenefitsConfig() { + log.info("Fetching economic benefits configuration"); + Map pebData = new LinkedHashMap<>(); + pebData.put("totalDevelopers", pebConfig.getTotalDevelopers() != null ? pebConfig.getTotalDevelopers() : 30); + pebData.put("avgCostPerDeveloper", pebConfig.getAvgCostPerDeveloper() != null ? pebConfig.getAvgCostPerDeveloper() : 100000.00); + pebData.put("timeDuration", pebConfig.getTimeDuration() != null ? pebConfig.getTimeDuration() : "Per Year"); + log.info("Economic benefits configuration retrieved successfully"); + return ResponseEntity.ok(new ServiceResponse(true, "Economic benefits configuration retrieved successfully", pebData)); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 442d5adcd..e5310e59b 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -528,4 +528,20 @@ spring.servlet.multipart.max-request-size=100MB # Purpose of property: Sets the timeout duration (in minutes) for executive dashboard operations. # possible values: number [1-60] # used in/for: Limiting the maximum execution time for executive dashboard processing -executive.dashboard.timeout.minutes=3 \ No newline at end of file +executive.dashboard.timeout.minutes=3 + +## Help & Support Configuration - Start +help.productDocumentationUrl=https://docs.example.com/product +help.apiDocumentationUrl=https://docs.example.com/api +help.videoTutorialsUrl=https://videos.example.com/tutorials +help.raiseTicketUrl=https://support.example.com/tickets +help.supportChannelUrl=https://chat.example.com/support +## Help & Support Configuration - End + +## Potential Economic Benefits Configuration - Start +peb.totalDevelopers=30 +peb.avgCostPerDeveloper=100000.00 +peb.timeDuration=Per Year +## Potential Economic Benefits Configuration - End + + diff --git a/src/test/java/com/publicissapient/kpidashboard/apis/appsetting/rest/HelpAndSupportControllerTest.java b/src/test/java/com/publicissapient/kpidashboard/apis/appsetting/rest/HelpAndSupportControllerTest.java new file mode 100644 index 000000000..8ef529bb7 --- /dev/null +++ b/src/test/java/com/publicissapient/kpidashboard/apis/appsetting/rest/HelpAndSupportControllerTest.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright 2014 CapitalOne, LLC. + * Further development Copyright 2022 Sapient Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +package com.publicissapient.kpidashboard.apis.appsetting.rest; + +import com.publicissapient.kpidashboard.apis.appsetting.config.HelpConfig; +import com.publicissapient.kpidashboard.apis.model.ServiceResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import java.net.URI; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Test class for HelpAndSupportController. + * + * @author Publicis Sapient + */ +@RunWith(MockitoJUnitRunner.class) +public class HelpAndSupportControllerTest { + + private static final String PRODUCT = "https://docs.example.com/product"; + private static final String API = "https://docs.example.com/api"; + private static final String VIDEOS_EXAMPLE_COM = "https://videos.example.com"; + private static final String TICKET = "https://support.example.com/ticket"; + private static final String CHANNEL = "https://support.example.com/channel"; + + @InjectMocks + private HelpAndSupportController helpAndSupportController; + + @Mock + private HelpConfig helpConfig; + + @Before + public void setUp() { + helpConfig = HelpConfig.builder() + .productDocumentationUrl(PRODUCT) + .apiDocumentationUrl(API) + .videoTutorialsUrl(VIDEOS_EXAMPLE_COM) + .raiseTicketUrl(TICKET) + .supportChannelUrl(CHANNEL) + .build(); + + helpAndSupportController = new HelpAndSupportController(); + helpAndSupportController.setHelpConfig(helpConfig); + + } + + @Test + public void testGetHelpConfig_Success() { + ResponseEntity response = helpAndSupportController.getHelpConfig(); + + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertNotNull(response.getBody()); + assertEquals(true, response.getBody().getSuccess()); + Map data = (Map) response.getBody().getData(); + assertEquals(5, data.size()); + assertEquals(PRODUCT, data.get("productDocumentation")); + assertEquals(API, data.get("apiDocumentation")); + assertEquals(VIDEOS_EXAMPLE_COM, data.get("videoTutorials")); + assertEquals(TICKET, data.get("raiseTicket")); + assertEquals(CHANNEL, data.get("supportChannel")); + } + + @Test + public void testGetHelpConfig_WithNullValues() { + helpConfig = HelpConfig.builder() + .productDocumentationUrl(null) + .apiDocumentationUrl(null) + .videoTutorialsUrl(VIDEOS_EXAMPLE_COM) + .raiseTicketUrl(TICKET) + .supportChannelUrl(CHANNEL) + .build(); + helpAndSupportController.setHelpConfig(helpConfig); + + ResponseEntity response = helpAndSupportController.getHelpConfig(); + + assertNotNull(response); + assertEquals(HttpStatus.OK, response.getStatusCode()); + Map data = (Map) response.getBody().getData(); + assertEquals("", data.get("productDocumentation")); + assertEquals("", data.get("apiDocumentation")); + } + + @Test + public void testRedirectToApiDocumentation_Success() { + ResponseEntity response = helpAndSupportController.redirectToApiDocumentation(); + + assertNotNull(response); + assertEquals(HttpStatus.FOUND, response.getStatusCode()); + assertEquals(URI.create(API), response.getHeaders().getLocation()); + } + + @Test + public void testRedirectToApiDocumentation_NotFound() { + helpConfig.setApiDocumentationUrl(""); + + ResponseEntity response = helpAndSupportController.redirectToApiDocumentation(); + + assertNotNull(response); + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); + } + + @Test + public void testRedirectToProductDocumentation_Success() { + ResponseEntity response = helpAndSupportController.redirectToProductDocumentation(); + + assertNotNull(response); + assertEquals(HttpStatus.FOUND, response.getStatusCode()); + assertEquals(URI.create(PRODUCT), response.getHeaders().getLocation()); + } + + @Test + public void testRedirectToProductDocumentation_NullUrl() { + helpConfig.setProductDocumentationUrl(null); + + ResponseEntity response = helpAndSupportController.redirectToProductDocumentation(); + + assertNotNull(response); + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); + } + + @Test + public void testRedirectToVideoTutorials_Success() { + ResponseEntity response = helpAndSupportController.redirectToVideoTutorials(); + + assertNotNull(response); + assertEquals(HttpStatus.FOUND, response.getStatusCode()); + assertEquals(URI.create(VIDEOS_EXAMPLE_COM), response.getHeaders().getLocation()); + } + + @Test + public void testRedirectToVideoTutorials_EmptyUrl() { + helpConfig.setVideoTutorialsUrl(" "); + + ResponseEntity response = helpAndSupportController.redirectToVideoTutorials(); + + assertNotNull(response); + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); + } + + @Test + public void testRedirectToRaiseTicket_Success() { + ResponseEntity response = helpAndSupportController.redirectToRaiseTicket(); + + assertNotNull(response); + assertEquals(HttpStatus.FOUND, response.getStatusCode()); + assertEquals(URI.create(TICKET), response.getHeaders().getLocation()); + } + + @Test + public void testRedirectToRaiseTicket_NotFound() { + helpConfig.setRaiseTicketUrl(""); + + ResponseEntity response = helpAndSupportController.redirectToRaiseTicket(); + + assertNotNull(response); + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); + } + + @Test + public void testRedirectToSupportChannel_Success() { + ResponseEntity response = helpAndSupportController.redirectToSupportChannel(); + + assertNotNull(response); + assertEquals(HttpStatus.FOUND, response.getStatusCode()); + assertEquals(URI.create(CHANNEL), response.getHeaders().getLocation()); + } + + @Test + public void testRedirectToSupportChannel_NotFound() { + helpConfig.setSupportChannelUrl(null); + + ResponseEntity response = helpAndSupportController.redirectToSupportChannel(); + + assertNotNull(response); + assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode()); + } +}