diff --git a/.github/workflows/swagger-json.yml b/.github/workflows/swagger-json.yml new file mode 100644 index 0000000..b9d58e6 --- /dev/null +++ b/.github/workflows/swagger-json.yml @@ -0,0 +1,100 @@ +name: Sync Swagger to AMRIT-Docs + +on: + push: + branches: [ main ] + workflow_dispatch: + +jobs: + swagger-sync: + runs-on: ubuntu-latest + + steps: + - name: Checkout API repo + uses: actions/checkout@v4 + + - name: Set up Java 17 + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 17 + cache: maven + + - name: Build API (skip tests) + run: mvn clean package -DENV_VAR=swagger -DskipTests -Dcheckstyle.skip=true + + - name: Install jq + run: sudo apt-get update && sudo apt-get install -y jq + + - name: Run API in swagger profile + run: | + mvn spring-boot:run \ + -DENV_VAR=swagger \ + -Dspring-boot.run.profiles=swagger \ + -Dcheckstyle.skip=true \ + -Dmaven.test.skip=true \ + -Dspring-boot.run.arguments="--server.port=9090" \ + > app.log 2>&1 & + echo $! > api_pid.txt + + - name: Wait for API & fetch Swagger + run: | + for i in {1..30}; do + CODE=$(curl --connect-timeout 2 --max-time 5 -s -o swagger_raw.json -w "%{http_code}" http://localhost:9090/v3/api-docs || true) + if [ "$CODE" = "200" ]; then + if jq . swagger_raw.json > helpline104-api.json; then + echo "Swagger generated successfully" + exit 0 + else + echo "Failed to parse swagger_raw.json with jq" + exit 1 + fi + fi + echo "Waiting for API... ($i)" + sleep 5 + done + + echo "Swagger not generated" + cat app.log || true + exit 1 + + - name: Stop API + if: always() + run: | + # Graceful shutdown of the process group + sleep 5 + # Force kill the process group if still running + if [ -f api_pid.txt ]; then + PID=$(cat api_pid.txt) + kill -TERM -- -"$PID" 2>/dev/null || true + sleep 2 + kill -9 -- -"$PID" 2>/dev/null || true + fi + # Fallback: kill any remaining java process on port 9090 + fuser -k 9090/tcp 2>/dev/null || true + + - name: Checkout AMRIT-Docs + uses: actions/checkout@v4 + with: + repository: PSMRI/AMRIT-Docs + token: ${{ secrets.DOCS_REPO_TOKEN }} + path: amrit-docs + + - name: Copy Swagger JSON + run: | + mkdir -p amrit-docs/docs/swagger + cp helpline104-api.json amrit-docs/docs/swagger/helpline104-api.json + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v8 + with: + token: ${{ secrets.DOCS_REPO_TOKEN }} + path: amrit-docs + branch: auto/swagger-update-helpline104-api + base: main + commit-message: Auto-update Helpline104-API swagger + title: Auto-update Helpline104-API swagger + delete-branch: true + body: | + This PR automatically updates the Helpline104-API Swagger JSON + from the latest main branch build. diff --git a/pom.xml b/pom.xml index ac49436..4349c78 100644 --- a/pom.xml +++ b/pom.xml @@ -249,6 +249,11 @@ 0.12.6 runtime + + com.h2database + h2 + runtime + diff --git a/src/main/java/com/iemr/helpline104/App.java b/src/main/java/com/iemr/helpline104/App.java index 4dd7bfd..01cbfda 100644 --- a/src/main/java/com/iemr/helpline104/App.java +++ b/src/main/java/com/iemr/helpline104/App.java @@ -26,6 +26,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Profile; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; @@ -60,6 +61,7 @@ public static void main(String[] args) { } @Bean + @Profile("!swagger") public IEMRApplBeans instantiateBeans() { return new IEMRApplBeans(); } @@ -83,6 +85,7 @@ public String hello(@PathVariable String name) { } @Bean + @Profile("!swagger") public RedisTemplate redisTemplate(RedisConnectionFactory factory) { RedisTemplate template = new RedisTemplate<>(); template.setConnectionFactory(factory); diff --git a/src/main/java/com/iemr/helpline104/config/InterceptorConfig.java b/src/main/java/com/iemr/helpline104/config/InterceptorConfig.java index 5a2df6e..746c8db 100644 --- a/src/main/java/com/iemr/helpline104/config/InterceptorConfig.java +++ b/src/main/java/com/iemr/helpline104/config/InterceptorConfig.java @@ -29,7 +29,10 @@ import com.iemr.helpline104.utils.http.HTTPRequestInterceptor; +import org.springframework.context.annotation.Profile; + @Configuration +@Profile("!swagger") public class InterceptorConfig implements WebMvcConfigurer { @Autowired diff --git a/src/main/java/com/iemr/helpline104/config/RedisConfig.java b/src/main/java/com/iemr/helpline104/config/RedisConfig.java index 755b966..5c15ba0 100644 --- a/src/main/java/com/iemr/helpline104/config/RedisConfig.java +++ b/src/main/java/com/iemr/helpline104/config/RedisConfig.java @@ -7,12 +7,14 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.context.annotation.Profile; import org.springframework.session.data.redis.config.ConfigureRedisAction; import com.iemr.helpline104.data.users.M_User; @Configuration @EnableCaching +@Profile("!swagger") public class RedisConfig { @Bean diff --git a/src/main/java/com/iemr/helpline104/config/SwaggerConfig.java b/src/main/java/com/iemr/helpline104/config/SwaggerConfig.java index e8a09c0..62e2f73 100644 --- a/src/main/java/com/iemr/helpline104/config/SwaggerConfig.java +++ b/src/main/java/com/iemr/helpline104/config/SwaggerConfig.java @@ -2,6 +2,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; @@ -11,14 +12,23 @@ @Configuration public class SwaggerConfig { - - @Bean - public OpenAPI customOpenAPI() { - return new OpenAPI().info(new - Info().title("Helpline 104 API").version("version").description("A microservice for the creation and management of beneficiaries.")) - .addSecurityItem(new SecurityRequirement().addList("my security")) - .components(new Components().addSecuritySchemes("my security", - new SecurityScheme().name("my security").type(SecurityScheme.Type.HTTP).scheme("bearer"))); + private static final String DEFAULT_SERVER_URL = "http://localhost:8091"; + + @Bean + public OpenAPI customOpenAPI(Environment env) { + String devUrl = env.getProperty("api.dev.url", DEFAULT_SERVER_URL); + String uatUrl = env.getProperty("api.uat.url", DEFAULT_SERVER_URL); + String demoUrl = env.getProperty("api.demo.url", DEFAULT_SERVER_URL); + return new OpenAPI() + .info(new Info().title("Helpline 104 API").version("1.0.0").description("Helpline 104 API for health advisory, disease surveillance, and medical information services.")) + .addSecurityItem(new SecurityRequirement().addList("my security")) + .components(new Components().addSecuritySchemes("my security", + new SecurityScheme().name("my security").type(SecurityScheme.Type.HTTP).scheme("bearer"))) + .servers(java.util.Arrays.asList( + new io.swagger.v3.oas.models.servers.Server().url(devUrl).description("Dev"), + new io.swagger.v3.oas.models.servers.Server().url(uatUrl).description("UAT"), + new io.swagger.v3.oas.models.servers.Server().url(demoUrl).description("Demo") + )); } } diff --git a/src/main/java/com/iemr/helpline104/utils/FilterConfig.java b/src/main/java/com/iemr/helpline104/utils/FilterConfig.java index 065954b..8f425a8 100644 --- a/src/main/java/com/iemr/helpline104/utils/FilterConfig.java +++ b/src/main/java/com/iemr/helpline104/utils/FilterConfig.java @@ -3,10 +3,12 @@ import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.core.Ordered; import org.springframework.beans.factory.annotation.Value; @Configuration +@Profile("!swagger") public class FilterConfig { @Value("${cors.allowed-origins}") diff --git a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java index cdba5a8..f15f081 100644 --- a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java @@ -6,6 +6,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -19,6 +20,7 @@ import jakarta.servlet.http.HttpServletRequest; @Component +@Profile("!swagger") public class JwtAuthenticationUtil { @Autowired diff --git a/src/main/java/com/iemr/helpline104/utils/JwtUtil.java b/src/main/java/com/iemr/helpline104/utils/JwtUtil.java index bc4c659..5317636 100644 --- a/src/main/java/com/iemr/helpline104/utils/JwtUtil.java +++ b/src/main/java/com/iemr/helpline104/utils/JwtUtil.java @@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import io.jsonwebtoken.Claims; @@ -12,6 +13,7 @@ import io.jsonwebtoken.security.Keys; @Component +@Profile("!swagger") public class JwtUtil { @Value("${jwt.secret}") diff --git a/src/main/java/com/iemr/helpline104/utils/TokenDenylist.java b/src/main/java/com/iemr/helpline104/utils/TokenDenylist.java index fb53ef5..bfb22dd 100644 --- a/src/main/java/com/iemr/helpline104/utils/TokenDenylist.java +++ b/src/main/java/com/iemr/helpline104/utils/TokenDenylist.java @@ -4,17 +4,21 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; @Component +@Profile("!swagger") public class TokenDenylist { private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); private static final String PREFIX = "denied_"; @Autowired + @Qualifier("genericRedisTemplate") private RedisTemplate redisTemplate; private String getKey(String jti) { diff --git a/src/main/java/com/iemr/helpline104/utils/http/HTTPRequestInterceptor.java b/src/main/java/com/iemr/helpline104/utils/http/HTTPRequestInterceptor.java index 693170a..7036833 100644 --- a/src/main/java/com/iemr/helpline104/utils/http/HTTPRequestInterceptor.java +++ b/src/main/java/com/iemr/helpline104/utils/http/HTTPRequestInterceptor.java @@ -40,8 +40,10 @@ import jakarta.ws.rs.core.MediaType; import com.iemr.helpline104.utils.validator.Validator; +import org.springframework.context.annotation.Profile; @Component +@Profile("!swagger") public class HTTPRequestInterceptor implements HandlerInterceptor { private final Validator validator; diff --git a/src/main/java/com/iemr/helpline104/utils/redis/RedisStorage.java b/src/main/java/com/iemr/helpline104/utils/redis/RedisStorage.java index 69fb95e..e5595c1 100644 --- a/src/main/java/com/iemr/helpline104/utils/redis/RedisStorage.java +++ b/src/main/java/com/iemr/helpline104/utils/redis/RedisStorage.java @@ -28,9 +28,11 @@ import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.types.Expiration; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; @Component +@Profile("!swagger") public class RedisStorage { // @Autowired // private RedisConnection redisConnection;// = new RedisConnection(); diff --git a/src/main/java/com/iemr/helpline104/utils/sessionobject/SessionObject.java b/src/main/java/com/iemr/helpline104/utils/sessionobject/SessionObject.java index 3f54972..7f6c0f2 100644 --- a/src/main/java/com/iemr/helpline104/utils/sessionobject/SessionObject.java +++ b/src/main/java/com/iemr/helpline104/utils/sessionobject/SessionObject.java @@ -22,6 +22,7 @@ package com.iemr.helpline104.utils.sessionobject; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import com.google.gson.JsonElement; @@ -32,6 +33,7 @@ import com.iemr.helpline104.utils.redis.RedisStorage; @Component +@Profile("!swagger") public class SessionObject { diff --git a/src/main/java/com/iemr/helpline104/utils/validator/Validator.java b/src/main/java/com/iemr/helpline104/utils/validator/Validator.java index 6d41a79..a953085 100644 --- a/src/main/java/com/iemr/helpline104/utils/validator/Validator.java +++ b/src/main/java/com/iemr/helpline104/utils/validator/Validator.java @@ -26,7 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; - +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; import com.iemr.helpline104.utils.config.ConfigProperties; @@ -36,6 +36,7 @@ @Service +@Profile("!swagger") public class Validator { // private static SessionObject session; diff --git a/src/main/resources/104_swagger.properties b/src/main/resources/104_swagger.properties new file mode 100644 index 0000000..da9d6d9 --- /dev/null +++ b/src/main/resources/104_swagger.properties @@ -0,0 +1,23 @@ +server.port=8091 +# Primary DB – H2 in-memory (MySQL compatibility mode) +spring.datasource.url=jdbc:h2:mem:swaggerdb;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false +spring.datasource.username=SA +spring.datasource.password= +spring.datasource.driver-class-name=org.h2.Driver +# Secondary (Reporting) DB – H2 in-memory +secondary.datasource.url=jdbc:h2:mem:reportingdb;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false +secondary.datasource.username=SA +secondary.datasource.password= +secondary.datasource.driver-class-name=org.h2.Driver +# Common URLs (safe defaults) +common-url=http://localhost:8080 +sendSMSUrl=http://localhost:8080/sms/sendSMS +sendEmailGeneralUrl=http://localhost:8080/emailController/sendEmailGeneral +# Redis +spring.redis.host=localhost +# JWT +jwt.secret=${JWT_SECRET_KEY:#{T(java.util.UUID).randomUUID().toString()}} +# CORS +cors.allowed-origins=http://localhost:8091,http://127.0.0.1:9000 +# Logging +logging.file.name=logs/helpline104-api.log