diff --git a/pom.xml b/pom.xml index 0ae3d0b9..3a0191c9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iemr.common-API common-api - 3.4.0 + 3.6.0 war Common-API @@ -111,6 +111,12 @@ + + + com.google.firebase + firebase-admin + 9.4.3 + org.springframework.boot spring-boot-starter-data-jpa diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index a5e66660..d8865adf 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -32,6 +32,7 @@ identity-1097-api-url = @env.IDENTITY_1097_API_URL@ send-sms=@env.SEND_SMS@ sendSMSUrl = @env.SEND_SMS_URL@ source-address=@env.SMS_SOURCE_ADDRESS@ +sms-consent-source-address = @env.SMS_CONSENT_SOURCE_ADDRESS@ sms-username=@env.SMS_USERNAME@ sms-password=@env.SMS_PASSWORD@ send-message-url=@env.SMS_MESSAGE_URL@ @@ -40,6 +41,11 @@ send-message-url=@env.SMS_MESSAGE_URL@ start-sms-scheduler=true cron-scheduler-sms=0 0/1 * * * ? * +# Firebase Configuration +firebase.enabled=@env.FIREBASE_ENABLE@ +# if using file +firebase.credential-file=@env.FIREBASE_CREDENTIAL@ + #### Email Configuration send-email=@env.SEND_EMAIL@ spring.mail.host=@env.MAIL_HOST@ @@ -185,4 +191,5 @@ cors.allowed-origins=@env.CORS_ALLOWED_ORIGINS@ video-call-url=@env.VIDEO_CALL_URL@ jibri.output.path=@env.JIBRI_OUTPUT_PATH@ -video.recording.path=@env.VIDEO_RECORDING_PATH@ \ No newline at end of file +video.recording.path=@env.VIDEO_RECORDING_PATH@ +generateBeneficiaryIDs-api-url=@env.GEN_BENEFICIARY_IDS_API_URL@ diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 41881886..2289c2c0 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -32,6 +32,7 @@ identity-1097-api-url = ${IDENTITY_1097_API_URL} send-sms=${SEND_SMS} sendSMSUrl = ${SEND_SMS_URL} source-address=${SMS_SOURCE_ADDRESS} +sms-consent-source-address=${SMS_CONSENT_SOURCE_ADDRESS} sms-username=${SMS_USERNAME} sms-password=${SMS_PASSWORD} send-message-url=${SMS_MESSAGE_URL} @@ -185,6 +186,13 @@ captcha.enable-captcha=${ENABLE_CAPTCHA} cors.allowed-origins=${CORS_ALLOWED_ORIGINS} +# # Firebase Configuration +firebase.enabled=${FIREBASE_ENABLE} +# # if using file +firebase.credential-file=${FIREBASE_CREDENTIAL} + + video-call-url=${VIDEO_CALL_URL} jibri.output.path={JIBRI_OUTPUT_PATH} -video.recording.path={VIDEO_RECORDING_PATH} \ No newline at end of file +video.recording.path={VIDEO_RECORDING_PATH} +generateBeneficiaryIDs-api-url={GEN_BENEFICIARY_IDS_API_URL} diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 09a526dd..bea76523 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -208,3 +208,5 @@ captcha.enable-captcha=true cors.allowed-origins=http://localhost:* +### generate Beneficiary IDs URL +generateBeneficiaryIDs-api-url=/generateBeneficiaryController/generateBeneficiaryIDs diff --git a/src/main/java/com/iemr/common/CommonApplication.java b/src/main/java/com/iemr/common/CommonApplication.java index b9b797b2..e4a59994 100644 --- a/src/main/java/com/iemr/common/CommonApplication.java +++ b/src/main/java/com/iemr/common/CommonApplication.java @@ -29,7 +29,6 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; -import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.web.client.RestTemplate; diff --git a/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java b/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java new file mode 100644 index 00000000..ebb697ec --- /dev/null +++ b/src/main/java/com/iemr/common/config/firebase/FirebaseMessagingConfig.java @@ -0,0 +1,65 @@ +package com.iemr.common.config.firebase; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Base64; + +@Configuration +public class FirebaseMessagingConfig { + private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + + @Value("${firebase.enabled:false}") + private boolean firebaseEnabled; + + @Value("${firebase.credential-file:}") + private String firebaseCredentialFile; + + + @Bean + @ConditionalOnProperty(name = "firebase.enabled", havingValue = "true") + public FirebaseMessaging firebaseMessaging() throws IOException { + if (!firebaseEnabled) { + logger.error("⚠️ Firebase disabled by config"); + return null; + } + + try { + if (firebaseCredentialFile == null || firebaseCredentialFile.isBlank()) { + logger.error("⚠️ No Firebase credentials path provided"); + return null; // don't throw, app will still start + } + + GoogleCredentials credentials = GoogleCredentials.fromStream( + new ClassPathResource(firebaseCredentialFile).getInputStream() + ); + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(credentials) + .build(); + + FirebaseApp firebaseApp = FirebaseApp.getApps().isEmpty() + ? FirebaseApp.initializeApp(options) + : FirebaseApp.getInstance(); + + return FirebaseMessaging.getInstance(firebaseApp); + + } catch (Exception e) { + logger.error("⚠️ Firebase init failed: " + e.getMessage()); + return null; // keep app running + } + + } + +} diff --git a/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java b/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java index f016de3d..314b31ac 100644 --- a/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java +++ b/src/main/java/com/iemr/common/config/quartz/ScheduleForGrievanceDataSync.java @@ -37,3 +37,4 @@ public void execute() { } } + diff --git a/src/main/java/com/iemr/common/controller/beneficiaryConsent/BeneficiaryConsentController.java b/src/main/java/com/iemr/common/controller/beneficiaryConsent/BeneficiaryConsentController.java new file mode 100644 index 00000000..77492d89 --- /dev/null +++ b/src/main/java/com/iemr/common/controller/beneficiaryConsent/BeneficiaryConsentController.java @@ -0,0 +1,118 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.common.controller.beneficiaryConsent; + +import com.iemr.common.data.beneficiaryConsent.BeneficiaryConsentRequest; +import com.iemr.common.service.beneficiaryOTPHandler.BeneficiaryOTPHandler; +import com.iemr.common.utils.mapper.InputMapper; +import com.iemr.common.utils.response.OutputResponse; +import io.lettuce.core.dynamic.annotation.Param; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.ws.rs.core.MediaType; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +@RequestMapping(value = { "/beneficiaryConsent" }) +@RestController +public class BeneficiaryConsentController { + final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + private BeneficiaryOTPHandler beneficiaryOTPHandler; + + @Operation(summary = "Send Consent") + @RequestMapping(value = "/sendConsent", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + public String sendConsent(@Param(value = "{\"mobNo\":\"String\"}") @RequestBody String requestOBJ) { + + OutputResponse response = new OutputResponse(); + + try { + BeneficiaryConsentRequest obj = InputMapper.gson().fromJson(requestOBJ, BeneficiaryConsentRequest.class); + + String success = beneficiaryOTPHandler.sendOTP(obj); // method name unchanged if internal logic still uses 'OTP' + logger.info(success.toString()); + response.setResponse(success); + + + } catch (Exception e) { + response.setError(500, "error : " + e); + } + return response.toString(); + } + + @Operation(summary = "Validate Consent") + @RequestMapping(value = "/validateConsent", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + public String validateConsent(@Param(value = "{\"mobNo\":\"String\",\"otp\":\"Integer\"}") @RequestBody String requestOBJ) { + + OutputResponse response = new OutputResponse(); + + try { + BeneficiaryConsentRequest obj = InputMapper.gson().fromJson(requestOBJ, BeneficiaryConsentRequest.class); + + JSONObject responseOBJ = beneficiaryOTPHandler.validateOTP(obj); + if (responseOBJ != null) + response.setResponse(responseOBJ.toString()); + else + response.setError(500, "failure"); + + } catch (Exception e) { + logger.error("error in validating Consent : " + e); + response.setError(500, "error : " + e); + } + return response.toString(); + } + + @Operation(summary = "Resend Consent") + @RequestMapping(value = "/resendConsent", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON) + public String resendConsent(@Param(value = "{\"mobNo\":\"String\"}") @RequestBody String requestOBJ) { + logger.info(requestOBJ.toString()); + + OutputResponse response = new OutputResponse(); + + try { + BeneficiaryConsentRequest obj = InputMapper.gson().fromJson(requestOBJ, BeneficiaryConsentRequest.class); + + String success = beneficiaryOTPHandler.resendOTP(obj); + logger.info(success.toString()); + + if (success.contains("otp")) + response.setResponse(success); + else + response.setError(500, "failure"); + + } catch (Exception e) { + logger.error("error in re-sending Consent : " + e); + response.setError(500, "error : " + e); + } + return response.toString(); + } + + +} + + diff --git a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java new file mode 100644 index 00000000..a5f72bbf --- /dev/null +++ b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java @@ -0,0 +1,98 @@ +package com.iemr.common.controller.dynamicForm; + +import com.iemr.common.dto.dynamicForm.FieldDTO; +import com.iemr.common.dto.dynamicForm.FormDTO; +import com.iemr.common.dto.dynamicForm.ModuleDTO; +import com.iemr.common.service.dynamicForm.FormMasterService; +import com.iemr.common.utils.response.ApiResponse; +import jakarta.validation.Valid; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RequestMapping(value = "dynamicForm") +@RestController +public class DynamicFormController { + @Autowired + private FormMasterService formMasterService; + + @PostMapping(value = "createModule",headers = "Authorization") + public ResponseEntity> createModule(@Valid @RequestBody ModuleDTO moduleDTO) { + try { + Object result = formMasterService.createModule(moduleDTO); + return ResponseEntity.status(HttpStatus.OK) + .body(ApiResponse.success("Module created successfully", HttpStatus.OK.value(), result)); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ApiResponse.error("Invalid module data: " + e.getMessage(), HttpStatus.BAD_REQUEST.value(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Failed to create module", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); + } + } + + @PostMapping(value = "createForm",headers = "Authorization") + public ResponseEntity> createForm(@Valid @RequestBody FormDTO dto) { + try { + Object result = formMasterService.createForm(dto); + return ResponseEntity.status(HttpStatus.OK) + .body(ApiResponse.success("Form created successfully", HttpStatus.OK.value(), result)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Failed to create form", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); + } + } + + @PostMapping(value = "createFields",headers = "Authorization") + public ResponseEntity> createField(@Valid @RequestBody List dto) { + try { + Object result = formMasterService.createField(dto); + return ResponseEntity.status(HttpStatus.OK) + .body(ApiResponse.success("Fields created successfully", HttpStatus.OK.value(), result)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Failed to create fields", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); + } + } + + @PostMapping(value = "field/update",headers = "Authorization") + public ResponseEntity> updateField(@Valid @RequestBody FieldDTO dto) { + try { + Object result = formMasterService.updateField(dto); + return ResponseEntity.status(HttpStatus.OK) + .body(ApiResponse.success("Field updated successfully", HttpStatus.OK.value(), result)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Failed to update field", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); + } + } + + @DeleteMapping(value = "delete/{fieldId}/field",headers = "Authorization") + public ResponseEntity> deleteField(@PathVariable Long fieldId) { + try { + formMasterService.deleteField(fieldId); + return ResponseEntity.status(HttpStatus.OK) + .body(ApiResponse.success("Field deleted successfully", HttpStatus.OK.value(), null)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Failed to delete field", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); + } + } + + @GetMapping(value = "form/{formId}/fields") + public ResponseEntity> getStructuredForm(@PathVariable String formId) { + try { + Object result = formMasterService.getStructuredFormByFormId(formId); + return ResponseEntity.status(HttpStatus.OK) + .body(ApiResponse.success("Form structure fetched successfully", HttpStatus.OK.value(), result)); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Failed to fetch form structure", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); + } + } + + +} diff --git a/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java b/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java new file mode 100644 index 00000000..3bb10cfc --- /dev/null +++ b/src/main/java/com/iemr/common/controller/firebaseNotification/FirebaseNotificationController.java @@ -0,0 +1,61 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +* +/* +* AMRIT – Accessible Medical Records via Integrated Technology +*/ +package com.iemr.common.controller.firebaseNotification; + +import com.iemr.common.model.notification.NotificationMessage; +import com.iemr.common.model.notification.UserToken; +import com.iemr.common.service.firebaseNotification.FirebaseNotificationService; +import com.iemr.common.utils.exception.IEMRException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping(value= "/firebaseNotification",headers = "Authorization") +public class FirebaseNotificationController { + final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + FirebaseNotificationService firebaseNotificationService; + + @RequestMapping(value = "sendNotification",method = RequestMethod.POST,headers = "Authorization") + public String sendNotificationByToken(@RequestBody NotificationMessage notificationMessage){ + return firebaseNotificationService.sendNotification(notificationMessage); + } + + @RequestMapping(value = "updateToken",method = RequestMethod.POST,headers = "Authorization") + public String updateToken(@RequestBody UserToken userToken){ + return firebaseNotificationService.updateToken(userToken); + } + + @RequestMapping(value = "getToken",method = RequestMethod.GET,headers = "Authorization") + public String getUserToken() throws IEMRException { + + return firebaseNotificationService.getUserToken(); + } + + +} diff --git a/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java b/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java index 5fd3e281..d02eb3f2 100644 --- a/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java +++ b/src/main/java/com/iemr/common/controller/nhmdashboard/NHMDetailCallReportScheduler.java @@ -181,3 +181,4 @@ private BeneficiaryCall getCallDetail(DetailedCallReport detailedCallReport) { } } + diff --git a/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java b/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java index a2156af1..e04fffc5 100644 --- a/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java +++ b/src/main/java/com/iemr/common/controller/users/EmployeeSignatureController.java @@ -21,22 +21,28 @@ */ package com.iemr.common.controller.users; +import java.nio.charset.StandardCharsets; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.PropertySource; +import org.springframework.http.CacheControl; +import org.springframework.http.ContentDisposition; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; import com.google.gson.Gson; import com.iemr.common.data.users.EmployeeSignature; import com.iemr.common.service.users.EmployeeSignatureServiceImpl; -import com.iemr.common.utils.mapper.InputMapper; import com.iemr.common.utils.response.OutputResponse; import io.swagger.v3.oas.annotations.Operation; @@ -51,29 +57,45 @@ public class EmployeeSignatureController { @Autowired EmployeeSignatureServiceImpl employeeSignatureServiceImpl; - private InputMapper inputMapper = new InputMapper(); - private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); @Operation(summary = "Fetch file") @RequestMapping(value = "/{userID}", headers = "Authorization", method = { RequestMethod.GET }) public ResponseEntity fetchFile(@PathVariable("userID") Long userID) throws Exception { - OutputResponse response = new OutputResponse(); logger.debug("File download for userID" + userID); try { - EmployeeSignature userSignID = employeeSignatureServiceImpl.fetchSignature(userID); - return ResponseEntity.ok().contentType(MediaType.parseMediaType(userSignID.getFileType())) - .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + userSignID.getFileName() + "\"") - .body(userSignID.getSignature()); + String originalName = userSignID.getFileName(); + if (originalName == null || originalName.isBlank()) { + originalName = "signature"; + } + HttpHeaders responseHeaders = new HttpHeaders(); + responseHeaders.setContentDisposition( + ContentDisposition.attachment().filename(originalName, StandardCharsets.UTF_8).build()); + responseHeaders.setCacheControl(CacheControl.noStore()); + responseHeaders.add(HttpHeaders.PRAGMA, "no-cache"); + responseHeaders.setExpires(0); + MediaType mediaType; + try { + mediaType = MediaType.parseMediaType(userSignID.getFileType()); + } catch (InvalidMediaTypeException | NullPointerException e) { + mediaType = MediaType.APPLICATION_OCTET_STREAM; + } + + byte[] fileBytes = userSignID.getSignature(); // MUST be byte[] + if (fileBytes == null || fileBytes.length == 0) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Signature not found for userID: " + userID); + } + + return ResponseEntity.ok().headers(responseHeaders).contentType(mediaType).contentLength(fileBytes.length) + .body(fileBytes); } catch (Exception e) { logger.error("File download for userID failed with exception " + e.getMessage(), e); + throw new Exception("Error while downloading file. Please contact administrator.."); } - return ResponseEntity.badRequest().body(new byte[] {}); - } @Operation(summary = "Fetch file from central") diff --git a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java index 28c7e4b9..080c8762 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -1,8 +1,8 @@ /* -* AMRIT – Accessible Medical Records via Integrated Technology -* Integrated EHR (Electronic Health Records) Solution +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution * -* Copyright (C) "Piramal Swasthya Management and Research Institute" +* Copyright (C) "Piramal Swasthya Management and Research Institute" * * This file is part of AMRIT. * @@ -170,8 +170,8 @@ public String userAuthenticate( JSONObject serviceRoleMap = new JSONObject(); JSONArray serviceRoleList = new JSONArray(); JSONObject previlegeObj = new JSONObject(); - if (m_User.getUserName() != null - && (m_User.getDoLogout() == null || !m_User.getDoLogout()) + if (m_User.getUserName() != null + && (m_User.getDoLogout() == null || !m_User.getDoLogout()) && (m_User.getWithCredentials() != null && m_User.getWithCredentials())) { String tokenFromRedis = getConcurrentCheckSessionObjectAgainstUser( m_User.getUserName().trim().toLowerCase()); @@ -187,7 +187,7 @@ public String userAuthenticate( String refreshToken = null; if (mUser.size() == 1) { jwtToken = jwtUtil.generateToken(m_User.getUserName(), mUser.get(0).getUserID().toString()); - + User user = new User(); // Assuming the Users class exists user.setUserID(mUser.get(0).getUserID()); user.setUserName(mUser.get(0).getUserName()); @@ -278,15 +278,16 @@ public ResponseEntity refreshToken(@RequestBody Map request) // Get user details String userId = claims.get("userId", String.class); User user = iemrAdminUserServiceImpl.getUserById(Long.parseLong(userId)); - + // Validate that the user still exists and is active if (user == null) { logger.warn("Token validation failed: user not found for userId in token."); return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized."); } - - if (user.getM_status() == null || !"Active".equalsIgnoreCase(user.getM_status().getStatus())) { - logger.warn("Token validation failed: user account is inactive or not in 'Active' status."); + + if (user.getM_status() == null || !("Active".equalsIgnoreCase(user.getM_status().getStatus()) + || "New".equalsIgnoreCase(user.getM_status().getStatus()))) { + logger.warn("Token validation failed: user account is neither 'Active' nor 'New'."); return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized."); } // Generate new tokens @@ -294,7 +295,7 @@ public ResponseEntity refreshToken(@RequestBody Map request) Map tokens = new HashMap<>(); tokens.put("jwtToken", newJwt); - + // Generate and store a new refresh token (token rotation) String newRefreshToken = jwtUtil.generateRefreshToken(user.getUserName(), userId); String newJti = jwtUtil.getJtiFromToken(newRefreshToken); @@ -343,9 +344,10 @@ public String logOutUserFromConcurrentSession( deleteSessionObjectByGettingSessionDetails(previousTokenFromRedis); sessionObject.deleteSessionObject(previousTokenFromRedis); response.setResponse("User successfully logged out"); - } else + } else{ logger.error("Unable to fetch session from redis"); throw new IEMRException("Session error. Please try again later"); + } } } else { throw new IEMRException("Invalid request object"); @@ -360,7 +362,7 @@ public String logOutUserFromConcurrentSession( } /** - * + * * function to return session object against userName */ private String getConcurrentCheckSessionObjectAgainstUser(String userName) { @@ -466,7 +468,7 @@ public String superUserAuthenticate( resMap.put("isAuthenticated", /* Boolean.valueOf(true) */true); resMap.put("userName", mUser.getUserName()); jwtToken = jwtUtil.generateToken(m_User.getUserName(), mUser.getUserID().toString()); - + User user = new User(); // Assuming the Users class exists user.setUserID(mUser.getUserID()); user.setUserName(mUser.getUserName()); @@ -561,7 +563,7 @@ public String getLoginResponse(HttpServletRequest request) { if (authHeader.isEmpty()) { // Try JWT token from header first String jwtToken = request.getHeader("Jwttoken"); - + // If not in header, try cookie if (jwtToken == null) { Cookie[] cookies = request.getCookies(); @@ -574,15 +576,15 @@ public String getLoginResponse(HttpServletRequest request) { } } } - + if (jwtToken == null) { logger.warn("Authentication failed: no token found in header or cookies."); throw new IEMRException("Authentication failed. Please log in again."); } - + // Extract user ID from the JWT token String userId = jwtUtil.getUserIdFromToken(jwtToken); - + // Get user details and prepare response User user = iemrAdminUserServiceImpl.getUserById(Long.parseLong(userId)); if (user == null) { @@ -759,7 +761,7 @@ public String saveUserSecurityQuesAns( } /** - * + * * @return security qtns */ @Operation(summary = "Get security quetions") @@ -908,7 +910,7 @@ public String userLogout(HttpServletRequest request) { } /** - * + * * @param key * @return */ @@ -952,7 +954,7 @@ public String forceLogout(@RequestBody ForceLogoutRequestModel request, HttpServ if (token == null) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); outputResponse.setError(new RuntimeException("No JWT token found in request")); - return outputResponse.toString(); + return outputResponse.toString(); } // Validate the token: Check if it is expired or in the deny list @@ -989,7 +991,7 @@ private String getJwtTokenFromCookies(HttpServletRequest request) { return null; } - + @Operation(summary = "User force log out") @RequestMapping(value = "/userForceLogout", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON, headers = "Authorization") public String userForceLogout( @@ -1212,4 +1214,19 @@ private JSONObject prepareAuthenticationResponse(User mUser, String remoteAddres return iemrAdminUserServiceImpl.generateKeyAndValidateIP(responseObj, remoteAddress, remoteHost); } + @Operation(summary = "Get UserId based on userName") + @GetMapping(value = "/userName/{userName}", produces = MediaType.APPLICATION_JSON, headers = "Authorization") + public ResponseEntity getUserDetails(@PathVariable("userName") String userName) { + try { + List users = iemrAdminUserServiceImpl.getUserIdbyUserName(userName); + if (users.isEmpty()) { + return new ResponseEntity<>(Map.of("error", "UserName Not Found"), HttpStatus.NOT_FOUND); + } + User user = users.get(0); + return new ResponseEntity<>(Map.of("userName", user.getUserName(), "userId", user.getUserID()), HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>(Map.of("error", "Internal server error"), HttpStatus.INTERNAL_SERVER_ERROR); + } + + } } diff --git a/src/main/java/com/iemr/common/data/beneficiaryConsent/BeneficiaryConsentRequest.java b/src/main/java/com/iemr/common/data/beneficiaryConsent/BeneficiaryConsentRequest.java new file mode 100644 index 00000000..ac629a3c --- /dev/null +++ b/src/main/java/com/iemr/common/data/beneficiaryConsent/BeneficiaryConsentRequest.java @@ -0,0 +1,12 @@ +package com.iemr.common.data.beneficiaryConsent; + +import lombok.Data; + +@Data +public class BeneficiaryConsentRequest { + private String mobNo; + private int otp; + private String userName; + private String designation; + +} diff --git a/src/main/java/com/iemr/common/data/dynamic_from/FormDefinition.java b/src/main/java/com/iemr/common/data/dynamic_from/FormDefinition.java new file mode 100644 index 00000000..9e62b6d9 --- /dev/null +++ b/src/main/java/com/iemr/common/data/dynamic_from/FormDefinition.java @@ -0,0 +1,30 @@ +package com.iemr.common.data.dynamic_from; +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDateTime; +@Entity +@Data +@Table(name = "form_master") +public class FormDefinition { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "form_id") + private String formId; + + @Column(name = "form_name") + private String formName; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "module_id") + private FormModule module; + + @Column(name = "created_at") + private LocalDateTime createdAt = LocalDateTime.now(); + @Column(name = "version") + private Integer version; + +} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/data/dynamic_from/FormField.java b/src/main/java/com/iemr/common/data/dynamic_from/FormField.java new file mode 100644 index 00000000..39785ae9 --- /dev/null +++ b/src/main/java/com/iemr/common/data/dynamic_from/FormField.java @@ -0,0 +1,59 @@ +package com.iemr.common.data.dynamic_from; +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDateTime; + +@Entity +@Data +@Table(name = "form_fields") +public class FormField { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "form_id", referencedColumnName = "form_id") + private FormDefinition form; + + @Column(name = "section_title") + private String sectionTitle; + + @Column(name = "field_id") + private String fieldId; + + @Column(name = "label") + private String label; + + @Column(name = "type") + private String type; + + @Column(name = "is_required") + private Boolean isRequired; + + @Column(name = "is_visible") + private Boolean isVisible; + + @Column(name = "default_value") + private String defaultValue; + + @Column(name = "placeholder") + private String placeholder; + + @Column(name = "options", columnDefinition = "json") + private String options; + + @Column(name = "validation", columnDefinition = "json") + private String validation; // includes error messages now + + @Column(name = "conditional", columnDefinition = "json") + private String conditional; + + @Column(name = "sequence") + private Integer sequence; + + @Column(name = "created_at") + private LocalDateTime createdAt = LocalDateTime.now(); + +} diff --git a/src/main/java/com/iemr/common/data/dynamic_from/FormModule.java b/src/main/java/com/iemr/common/data/dynamic_from/FormModule.java new file mode 100644 index 00000000..ba5d0170 --- /dev/null +++ b/src/main/java/com/iemr/common/data/dynamic_from/FormModule.java @@ -0,0 +1,23 @@ +package com.iemr.common.data.dynamic_from; + +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDateTime; + +@Entity +@Data +@Table(name = "form_module") +public class FormModule { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "module_name") + private String moduleName; + + @Column(name = "created_at") + private LocalDateTime createdAt = LocalDateTime.now(); + +} diff --git a/src/main/java/com/iemr/common/data/userToken/UserTokenData.java b/src/main/java/com/iemr/common/data/userToken/UserTokenData.java new file mode 100644 index 00000000..0646972e --- /dev/null +++ b/src/main/java/com/iemr/common/data/userToken/UserTokenData.java @@ -0,0 +1,46 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +* +/* +* AMRIT – Accessible Medical Records via Integrated Technology +*/ +package com.iemr.common.data.userToken; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; + +import java.sql.Timestamp; + +@Entity +@Table(name = "user_tokens", schema = "db_iemr") +@Data +public class UserTokenData { + @Id + @Column(name = "user_id") + Integer userId; + @Column(name = "token") + String token; + @Column(name = "updated_at") + Timestamp updatedAt; +} diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FieldDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FieldDTO.java new file mode 100644 index 00000000..894f03c2 --- /dev/null +++ b/src/main/java/com/iemr/common/dto/dynamicForm/FieldDTO.java @@ -0,0 +1,25 @@ +package com.iemr.common.dto.dynamicForm; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class FieldDTO { + private Long id; + private String formId; + private String sectionTitle; + private String fieldId; + private String label; + private String type; + private Boolean isVisible; + private Boolean isRequired; + private String defaultValue; + private String placeholder; + private Integer sequence; + private String options; // ⬅️ changed from String to List + private String validation; // ⬅️ changed from String to Map + private String conditional; // ⬅️ changed from String to Map +} + diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FieldResponseDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FieldResponseDTO.java new file mode 100644 index 00000000..3415d91a --- /dev/null +++ b/src/main/java/com/iemr/common/dto/dynamicForm/FieldResponseDTO.java @@ -0,0 +1,24 @@ +package com.iemr.common.dto.dynamicForm; + +import lombok.Data; + +import java.util.List; +import java.util.Map; + +@Data +public class FieldResponseDTO { + private Long id; + private String formId; + private String sectionTitle; + private String fieldId; + private String label; + private Boolean visible; + private String type; + private Boolean isRequired; + private String defaultValue; + private String placeholder; + private Integer sequence; + private List options; + private Map validation; + private Map conditional; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FormDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FormDTO.java new file mode 100644 index 00000000..24788cac --- /dev/null +++ b/src/main/java/com/iemr/common/dto/dynamicForm/FormDTO.java @@ -0,0 +1,10 @@ +package com.iemr.common.dto.dynamicForm; + +import lombok.Data; + +@Data +public class FormDTO { + private String formId; + private String formName; + private Long moduleId; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/FormResponseDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FormResponseDTO.java new file mode 100644 index 00000000..26563927 --- /dev/null +++ b/src/main/java/com/iemr/common/dto/dynamicForm/FormResponseDTO.java @@ -0,0 +1,13 @@ +package com.iemr.common.dto.dynamicForm; + +import lombok.Data; + +import java.util.List; + +@Data +public class FormResponseDTO { + private Integer version; + private String formId; + private String formName; + private List sections; +} diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/GroupedFieldResponseDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/GroupedFieldResponseDTO.java new file mode 100644 index 00000000..840c5097 --- /dev/null +++ b/src/main/java/com/iemr/common/dto/dynamicForm/GroupedFieldResponseDTO.java @@ -0,0 +1,11 @@ +package com.iemr.common.dto.dynamicForm; + +import lombok.Data; + +import java.util.List; + +@Data +public class GroupedFieldResponseDTO { + private String sectionTitle; + private List fields; +} diff --git a/src/main/java/com/iemr/common/dto/dynamicForm/ModuleDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/ModuleDTO.java new file mode 100644 index 00000000..3f4240c4 --- /dev/null +++ b/src/main/java/com/iemr/common/dto/dynamicForm/ModuleDTO.java @@ -0,0 +1,8 @@ +package com.iemr.common.dto.dynamicForm; + +import lombok.Data; + +@Data +public class ModuleDTO { + private String moduleName; +} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java b/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java index 431a267a..8e364eb3 100644 --- a/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java +++ b/src/main/java/com/iemr/common/dto/identity/CommonIdentityDTO.java @@ -54,6 +54,8 @@ public class CommonIdentityDTO { private Integer beneficiaryRegId; private Integer communityId; private String community; + private Boolean isConsent=false; + private Timestamp dob; private Integer ageAtMarriage; private Integer educationId; diff --git a/src/main/java/com/iemr/common/mapper/CommonIdentityMapperDecorator.java b/src/main/java/com/iemr/common/mapper/CommonIdentityMapperDecorator.java index 5e8034af..1480f306 100644 --- a/src/main/java/com/iemr/common/mapper/CommonIdentityMapperDecorator.java +++ b/src/main/java/com/iemr/common/mapper/CommonIdentityMapperDecorator.java @@ -168,8 +168,17 @@ public CommonIdentityDTO beneficiaryModelCommonIdentityDTO(BeneficiaryModel bene Short maritalStatusID = beneficiary.getMaritalStatusID(); if (maritalStatusID != null) { commonIdentityDTO.setMaritalStatusId(maritalStatusID.intValue()); - commonIdentityDTO.setMaritalStatus( - maritalStatusMapper.maritalStatusByIDToResponse(maritalStatusID.intValue()).getStatus()); + var model = maritalStatusMapper.maritalStatusByIDToResponse(maritalStatusID.intValue()); + if (model != null) { + commonIdentityDTO.setMaritalStatus(model.getStatus()); + } else { + // Option 1: Return null + commonIdentityDTO.setMaritalStatus(null); + // Option 2: Or set a default + // commonIdentityDTO.setMaritalStatus("Unknown"); + // Option 3: Or log a warning + // logger.warn("Invalid maritalStatusID: {}", maritalStatusID); + } } commonIdentityDTO.setMaritalStatus(beneficiary.getMaritalStatusName()); commonIdentityDTO.setGender(beneficiary.getGenderName()); diff --git a/src/main/java/com/iemr/common/model/beneficiary/BeneficiaryModel.java b/src/main/java/com/iemr/common/model/beneficiary/BeneficiaryModel.java index dfb76d00..ed7c9cad 100644 --- a/src/main/java/com/iemr/common/model/beneficiary/BeneficiaryModel.java +++ b/src/main/java/com/iemr/common/model/beneficiary/BeneficiaryModel.java @@ -78,6 +78,10 @@ public class BeneficiaryModel implements Comparable { // private List outboundCallRequests; // private List beneficiaryCalls; // private List feedbacks; + @Expose + private Boolean isConsent=false; + + @Expose private String beneficiaryID; @Expose diff --git a/src/main/java/com/iemr/common/model/notification/NotificationMessage.java b/src/main/java/com/iemr/common/model/notification/NotificationMessage.java new file mode 100644 index 00000000..58343034 --- /dev/null +++ b/src/main/java/com/iemr/common/model/notification/NotificationMessage.java @@ -0,0 +1,38 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +* +/* +* AMRIT – Accessible Medical Records via Integrated Technology +*/ +package com.iemr.common.model.notification; + +import lombok.Data; + +import java.util.Map; + +@Data +public class NotificationMessage { + private String appType; + private String token; + private String title; + private String body; + private Map data; +} diff --git a/src/main/java/com/iemr/common/model/notification/UserToken.java b/src/main/java/com/iemr/common/model/notification/UserToken.java new file mode 100644 index 00000000..3ea36588 --- /dev/null +++ b/src/main/java/com/iemr/common/model/notification/UserToken.java @@ -0,0 +1,33 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +* +/* +* AMRIT – Accessible Medical Records via Integrated Technology +*/ +package com.iemr.common.model.notification; + +import lombok.Data; + +@Data +public class UserToken { + Integer userId; + String token; +} diff --git a/src/main/java/com/iemr/common/repo/userToken/UserTokenRepo.java b/src/main/java/com/iemr/common/repo/userToken/UserTokenRepo.java new file mode 100644 index 00000000..817f26f0 --- /dev/null +++ b/src/main/java/com/iemr/common/repo/userToken/UserTokenRepo.java @@ -0,0 +1,31 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +* +/* +* AMRIT – Accessible Medical Records via Integrated Technology +*/ +package com.iemr.common.repo.userToken; + +import com.iemr.common.data.userToken.UserTokenData; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserTokenRepo extends JpaRepository { +} diff --git a/src/main/java/com/iemr/common/repository/dynamic_form/FieldRepository.java b/src/main/java/com/iemr/common/repository/dynamic_form/FieldRepository.java new file mode 100644 index 00000000..4aea5698 --- /dev/null +++ b/src/main/java/com/iemr/common/repository/dynamic_form/FieldRepository.java @@ -0,0 +1,12 @@ +package com.iemr.common.repository.dynamic_form; + +import com.iemr.common.data.dynamic_from.FormField; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface FieldRepository extends JpaRepository { + List findByForm_FormIdOrderBySequenceAsc(String formId); +} diff --git a/src/main/java/com/iemr/common/repository/dynamic_form/FormRepository.java b/src/main/java/com/iemr/common/repository/dynamic_form/FormRepository.java new file mode 100644 index 00000000..50331dd2 --- /dev/null +++ b/src/main/java/com/iemr/common/repository/dynamic_form/FormRepository.java @@ -0,0 +1,14 @@ +package com.iemr.common.repository.dynamic_form; + +import com.iemr.common.data.dynamic_from.FormDefinition; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface FormRepository extends JpaRepository { + Optional findByFormId(String formId); + List findByModule_Id(Long moduleId); +} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/repository/dynamic_form/ModuleRepository.java b/src/main/java/com/iemr/common/repository/dynamic_form/ModuleRepository.java new file mode 100644 index 00000000..bafbfbea --- /dev/null +++ b/src/main/java/com/iemr/common/repository/dynamic_form/ModuleRepository.java @@ -0,0 +1,10 @@ +package com.iemr.common.repository.dynamic_form; + +import com.iemr.common.data.dynamic_from.FormModule; +import org.springframework.data.repository.CrudRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ModuleRepository extends CrudRepository { + +} diff --git a/src/main/java/com/iemr/common/repository/sms/SMSTemplateRepository.java b/src/main/java/com/iemr/common/repository/sms/SMSTemplateRepository.java index e5d741f0..06745eb0 100644 --- a/src/main/java/com/iemr/common/repository/sms/SMSTemplateRepository.java +++ b/src/main/java/com/iemr/common/repository/sms/SMSTemplateRepository.java @@ -22,6 +22,7 @@ package com.iemr.common.repository.sms; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; @@ -56,7 +57,9 @@ public List getSMSTemplateByProviderServiceMapIDAndSMSTypeID( @Query("select smsTemplate.dltTemplateId from SMSTemplate smsTemplate where smsTemplate.smsTemplateID = :smsTemplateID and smsTemplate.deleted <> true") public String findDLTTemplateID(@Param("smsTemplateID") Integer smsTemplateID ); - + + Optional findBySmsTemplateName(String smsTemplateName); + SMSTemplate findBySmsTemplateID(Integer smsTemplateID); } diff --git a/src/main/java/com/iemr/common/service/beneficiary/IdentityBeneficiaryServiceImpl.java b/src/main/java/com/iemr/common/service/beneficiary/IdentityBeneficiaryServiceImpl.java index 697322c6..2e6ac1d4 100644 --- a/src/main/java/com/iemr/common/service/beneficiary/IdentityBeneficiaryServiceImpl.java +++ b/src/main/java/com/iemr/common/service/beneficiary/IdentityBeneficiaryServiceImpl.java @@ -26,15 +26,12 @@ import java.util.HashSet; import java.util.List; +import com.google.gson.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import com.iemr.common.dto.identity.BeneficiariesDTO; import com.iemr.common.dto.identity.BeneficiariesPartialDTO; import com.iemr.common.dto.identity.IdentityEditDTO; @@ -54,20 +51,20 @@ public class IdentityBeneficiaryServiceImpl implements IdentityBeneficiaryServic Logger logger = LoggerFactory.getLogger(this.getClass().getName()); private static HttpUtils httpUtils = new HttpUtils(); private InputMapper inputMapper = new InputMapper(); - private String identityBaseURL = ConfigProperties.getPropertyByName("identity-api-url"); - private String identity1097BaseURL = ConfigProperties.getPropertyByName("identity-1097-api-url"); + @Value("${identity-api-url}") + private String identityBaseURL; + @Value("${identity-1097-api-url}") + private String identity1097BaseURL; + private static final String IDENTITY_BASE_URL = "IDENTITY_BASE_URL"; - private static final String BEN_GEN = ConfigProperties.getPropertyByName("genben-api"); - private static final String BEN_GEN_API_URL = ConfigProperties.getPropertyByName("generateBeneficiaryIDs-api-url"); - // public IdentityBeneficiaryServiceImpl() - // { - // - //// if (urlRequest == null) - //// { - //// urlRequest = ConfigProperties.getPropertyByName("identity-api-url"); - //// } - // } + @Value("${genben-api}") + private String BEN_GEN ; + + + @Value("${generateBeneficiaryIDs-api-url}") + private String BEN_GEN_API_URL ; + @Override // public List getBeneficiaryListByIDs() {// search by regID @@ -399,23 +396,38 @@ public List getBeneficiaryListByGovId(String identity, String @Override public String getIdentityResponse(String request, String auth, Boolean is1097) throws IEMRException { - String result; HashMap header = new HashMap<>(); if (auth != null) { header.put("Authorization", auth); } - result = httpUtils.post(ConfigProperties.getPropertyByName("identity-api-url-benCreate") - .replace(IDENTITY_BASE_URL, (is1097 ? identity1097BaseURL : identityBaseURL)), request, header); + String apiUrl = ConfigProperties.getPropertyByName("identity-api-url-benCreate") + .replace(IDENTITY_BASE_URL, (is1097 ? identity1097BaseURL : identityBaseURL)); + logger.info("Calling URL: {}", apiUrl); + logger.info("Request Payload: {}", request); - OutputResponse identityResponse = inputMapper.gson().fromJson(result, OutputResponse.class); - if (identityResponse.getStatusCode() == OutputResponse.USERID_FAILURE) { - throw new IEMRException(identityResponse.getErrorMessage()); + result = httpUtils.post(apiUrl, request, header); + + if (result == null || result.isEmpty()) { + logger.error("Empty response from Identity API"); + throw new IEMRException("No response received from Identity API"); + } + + try { + OutputResponse identityResponse = inputMapper.gson().fromJson(result, OutputResponse.class); + if (identityResponse.getStatusCode() == OutputResponse.USERID_FAILURE) { + throw new IEMRException(identityResponse.getErrorMessage()); + } + } catch (JsonSyntaxException e) { + logger.error("JSON parsing error: {}", e.getMessage()); + throw new IEMRException("Invalid response format from Identity API"); } + return result; } + public Integer editIdentityEditDTO(IdentityEditDTO identityEditDTO, String auth, Boolean is1097) throws IEMRException { JsonParser parser = new JsonParser(); @@ -517,8 +529,11 @@ public List generateBeneficiaryIDs(String request, String a if (auth != null) { header.put("Authorization", auth); } + + logger.info("Request to generate ben IDs: " + request); + logger.info("Generating ben IDs API URL: " + BEN_GEN + BEN_GEN_API_URL); result = httpUtils.post(BEN_GEN + BEN_GEN_API_URL, request, header); - +logger.info("Response from generate ben IDs: " + result); OutputResponse identityResponse = inputMapper.gson().fromJson(result, OutputResponse.class); if (identityResponse.getStatusCode() == OutputResponse.USERID_FAILURE) { diff --git a/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java b/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java index 7f6f6266..aa0c2a71 100644 --- a/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java +++ b/src/main/java/com/iemr/common/service/beneficiary/RegisterBenificiaryServiceImpl.java @@ -30,6 +30,8 @@ import java.util.ArrayList; import java.util.List; +import com.iemr.common.service.welcomeSms.WelcomeBenificarySmsService; +import com.iemr.common.service.welcomeSms.WelcomeBenificarySmsServiceImpl; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,9 +75,14 @@ public class RegisterBenificiaryServiceImpl implements RegisterBenificiaryServic @Autowired IdentityBenEditMapper identityBenEditMapper; + @Autowired + private WelcomeBenificarySmsService welcomeBenificarySmsService; + @Autowired Validator validator; + + @Autowired OutboundHistoryRepository outboundHistoryRepository; @@ -170,17 +177,28 @@ private int updateDemographics(BeneficiaryDemographicsModel i_BenDemographics) { @Override public String save(BeneficiaryModel beneficiaryModel, HttpServletRequest servletRequest) throws Exception { - // logger.info("benificiaryDetails: " + beneficiaryModel); + logger.info("benificiaryDetails: " + beneficiaryModel); CommonIdentityDTO identityDTO = identityMapper.beneficiaryModelCommonIdentityDTO(beneficiaryModel); + setSaveDemographicDetails(identityDTO,beneficiaryModel); - // identityDTO.setOtherFields(beneficiaryModel.getOtherFields()); +// identityDTO.setOtherFields(beneficiaryModel.getOtherFields()); + identityDTO.setIsConsent(beneficiaryModel.getIsConsent()); +// identityDTO.setIsDeath(beneficiaryModel.getIsDeath()); +// identityDTO.setIsDeathValue(beneficiaryModel.getIsDeathValue()); +// identityDTO.setDateOfDeath(beneficiaryModel.getDateOfDeath()); +// identityDTO.setPlaceOfDeath(beneficiaryModel.getPlaceOfDeath()); +// identityDTO.setOtherPlaceOfDeath(beneficiaryModel.getOtherPlaceOfDeath()); +// identityDTO.setTimeOfDeath(beneficiaryModel.getTimeOfDeath()); + + identityDTO.setFaceEmbedding(beneficiaryModel.getFaceEmbedding()); identityDTO.setEmergencyRegistration(beneficiaryModel.isEmergencyRegistration()); identityDTO .setBenFamilyDTOs(identityMapper.benPhoneMapListToBenFamilyDTOList(beneficiaryModel.getBenPhoneMaps())); String request = new Gson().toJson(identityDTO); + if (beneficiaryModel.getIs1097() == null) beneficiaryModel.setIs1097(false); @@ -200,10 +218,18 @@ public String save(BeneficiaryModel beneficiaryModel, HttpServletRequest servlet } else { return response.toString(); } + if(beneficiary!=null){ + if(beneficiary.getBenPhoneMaps().get(0).getPhoneNo()!=null){ + welcomeBenificarySmsService.sendWelcomeSMStoBenificiary(beneficiary.getBenPhoneMaps().get(0).getPhoneNo(),beneficiary.getFirstName()+" "+beneficiary.getLastName(),beneficiary.getBeneficiaryID()); + } + } + } return OutputMapper.gson().toJson(beneficiary); } + + private void setSaveDemographicDetails(CommonIdentityDTO identityDTO, BeneficiaryModel beneficiaryModel) { if(null != beneficiaryModel.getI_bendemographics()) { identityDTO.setCommunity(beneficiaryModel.getI_bendemographics().getCommunityName()); diff --git a/src/main/java/com/iemr/common/service/beneficiaryOTPHandler/BeneficiaryOTPHandler.java b/src/main/java/com/iemr/common/service/beneficiaryOTPHandler/BeneficiaryOTPHandler.java new file mode 100644 index 00000000..234640a8 --- /dev/null +++ b/src/main/java/com/iemr/common/service/beneficiaryOTPHandler/BeneficiaryOTPHandler.java @@ -0,0 +1,14 @@ +package com.iemr.common.service.beneficiaryOTPHandler; + +import com.iemr.common.data.beneficiaryConsent.BeneficiaryConsentRequest; +import com.iemr.common.data.otp.OTPRequestParsor; +import org.json.JSONObject; + +public interface BeneficiaryOTPHandler { + public String sendOTP(BeneficiaryConsentRequest obj) throws Exception; + + public JSONObject validateOTP(BeneficiaryConsentRequest obj) throws Exception; + + public String resendOTP(BeneficiaryConsentRequest obj) throws Exception; + +} diff --git a/src/main/java/com/iemr/common/service/beneficiaryOTPHandler/BeneficiaryOTPHandlerImpl.java b/src/main/java/com/iemr/common/service/beneficiaryOTPHandler/BeneficiaryOTPHandlerImpl.java new file mode 100644 index 00000000..42e0acfe --- /dev/null +++ b/src/main/java/com/iemr/common/service/beneficiaryOTPHandler/BeneficiaryOTPHandlerImpl.java @@ -0,0 +1,236 @@ +/* + * AMRIT – Accessible Medical Records via Integrated Technology + * Integrated EHR (Electronic Health Records) Solution + * + * Copyright (C) "Piramal Swasthya Management and Research Institute" + * + * This file is part of AMRIT. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see https://www.gnu.org/licenses/. + */ +package com.iemr.common.service.beneficiaryOTPHandler; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.primitives.Ints; +import com.iemr.common.data.beneficiaryConsent.BeneficiaryConsentRequest; +import com.iemr.common.data.otp.OTPRequestParsor; +import com.iemr.common.data.sms.SMSTemplate; +import com.iemr.common.data.sms.SMSType; +import com.iemr.common.repository.sms.SMSTemplateRepository; +import com.iemr.common.repository.sms.SMSTypeRepository; +import com.iemr.common.service.otp.OTPHandler; +import com.iemr.common.service.users.IEMRAdminUserServiceImpl; +import com.iemr.common.utils.config.ConfigProperties; +import com.iemr.common.utils.http.HttpUtils; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.util.*; +import java.util.concurrent.TimeUnit; + +@Service +public class BeneficiaryOTPHandlerImpl implements BeneficiaryOTPHandler { + + @Autowired + HttpUtils httpUtils; + @Autowired + private IEMRAdminUserServiceImpl iEMRAdminUserServiceImpl; + + final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + @Autowired + SMSTemplateRepository smsTemplateRepository; + private LoadingCache otpCache; + + @Autowired + SMSTypeRepository smsTypeRepository; + @Value("${sms-template-name}") + private String smsTemplateName ; + + private String smsTemplate; + @Value("${sms-username}") + private String smsUserName; + + @Value("${sms-password}") + private String smsPassword ; + + @Value("${sms-message-type}") + private String smsMessageType; + + @Value("${sms-entityid}") + private String smsEntityId; + + @Value("${sms-consent-source-address}") + + private String smsConsentSourceAddress ; + @Value("${send-message-url}") + private String SMS_GATEWAY_URL; + + private static final Integer EXPIRE_MIN = 5; + + // Constructor for new object creation + public BeneficiaryOTPHandlerImpl() { + otpCache = CacheBuilder.newBuilder().expireAfterWrite(EXPIRE_MIN, TimeUnit.MINUTES) + .build(new CacheLoader() { + public String load(String key) { + return "0"; + } + }); + } + + /*** + * @param obj + * @return success if OTP sent successfully + */ + @Override + public String sendOTP(BeneficiaryConsentRequest obj) throws Exception { + int otp = generateOTP(obj.getMobNo()); + return sendSMS(otp, obj); + } + + /*** + * @param obj + * @return OTP verification success or failure + * + */ + @Override + public JSONObject validateOTP(BeneficiaryConsentRequest obj) throws Exception { + String cachedOTP = otpCache.get(obj.getMobNo()); + String inputOTPEncrypted = getEncryptedOTP(obj.getOtp()); + + if (cachedOTP.equalsIgnoreCase(inputOTPEncrypted)) { + JSONObject responseObj = new JSONObject(); + responseObj.put("userName", obj.getMobNo()); + responseObj.put("userID", obj.getMobNo()); + + JSONObject responseOBJ = iEMRAdminUserServiceImpl.generateKeyPostOTPValidation(responseObj); + + return responseOBJ; + } else { + throw new Exception("Please enter valid OTP"); + } + + } + + /*** + * @param obj + * @return success if OTP re-sent successfully + */ + @Override + public String resendOTP(BeneficiaryConsentRequest obj) throws Exception { + int otp = generateOTP(obj.getMobNo()); + return sendSMS(otp, obj); + } + + // generate 6 digit random no # + public int generateOTP(String authKey) throws Exception { + String generatedPassword = null; + Random random = SecureRandom.getInstanceStrong(); + int otp = 100000 + random.nextInt(900000); + + generatedPassword = getEncryptedOTP(otp); + + if (otpCache != null) + otpCache.put(authKey, generatedPassword); + else { + BeneficiaryOTPHandlerImpl obj = new BeneficiaryOTPHandlerImpl(); + obj.otpCache.put(authKey, generatedPassword); + } + return otp; + } + + // SHA-256 encoding logic implemented + private String getEncryptedOTP(int otp) throws Exception { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] bytes = md.digest(Ints.toByteArray(otp)); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < bytes.length; i++) { + sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); + } + + return sb.toString(); + } + + // send SMS to beneficiary + + + public String sendSMS(int otp, BeneficiaryConsentRequest obj) { + logger.info("templateName"+smsTemplateName); + + final RestTemplate restTemplate = new RestTemplate(); + + Optional smsTemplateData = smsTemplateRepository.findBySmsTemplateName(smsTemplateName); + List smsTemplateAllData = (List) smsTemplateRepository.findAll(); + logger.info("AllData"+smsTemplateAllData.stream().toArray()); + + if(smsTemplateData.isPresent()){ + smsTemplate = smsTemplateRepository.findBySmsTemplateID(smsTemplateData.get().getSmsTemplateID()).getSmsTemplate(); + + } + + String sendSMSAPI = SMS_GATEWAY_URL; + logger.info("sms template"+smsTemplate); + + try { + String message = smsTemplate + .replace("$$OTP$$",String.valueOf(otp)); + + // Build payload + Map payload = new HashMap<>(); + payload.put("customerId",smsUserName); + payload.put("destinationAddress", obj.getMobNo()); + payload.put("message", message); + payload.put("sourceAddress", smsConsentSourceAddress); + payload.put("messageType", smsMessageType); + payload.put("dltTemplateId", smsTemplateData.get().getDltTemplateId()); + payload.put("entityId",smsEntityId ); + payload.put("otp", true); + // Set headers + HttpHeaders headers = new HttpHeaders(); + String auth = smsUserName + ":" + smsPassword; + headers.add("Authorization", + "Basic " + Base64.getEncoder().encodeToString(auth.getBytes())); + + headers.setContentType(MediaType.APPLICATION_JSON); + logger.info("payload: "+payload); + HttpEntity> request = new HttpEntity<>(payload, headers); + + // Call API + ResponseEntity response = restTemplate.postForEntity(sendSMSAPI, request, String.class); + logger.info("sms-response:"+response.getBody()); + if(response.getStatusCode().value()==200){ + return "OTP sent successfully on register mobile number"; + }else { + return "Fail"; + + } + + } catch (Exception e) { + return "Error sending SMS: " + e.getMessage(); + } + } + +} diff --git a/src/main/java/com/iemr/common/service/callhandling/BeneficiaryCallServiceImpl.java b/src/main/java/com/iemr/common/service/callhandling/BeneficiaryCallServiceImpl.java index 1a9474ff..c28d41cb 100644 --- a/src/main/java/com/iemr/common/service/callhandling/BeneficiaryCallServiceImpl.java +++ b/src/main/java/com/iemr/common/service/callhandling/BeneficiaryCallServiceImpl.java @@ -1684,8 +1684,11 @@ public List getBeneficiaryListFromMapper(List createField(List dto); + FormField updateField(FieldDTO dto); + + FormResponseDTO getStructuredFormByFormId(String formId); + + void deleteField(Long fieldId); +} diff --git a/src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java b/src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java new file mode 100644 index 00000000..19864742 --- /dev/null +++ b/src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java @@ -0,0 +1,176 @@ +package com.iemr.common.service.dynamicForm; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.iemr.common.data.dynamic_from.FormDefinition; +import com.iemr.common.data.dynamic_from.FormField; +import com.iemr.common.data.dynamic_from.FormModule; +import com.iemr.common.dto.dynamicForm.*; +import com.iemr.common.repository.dynamic_form.FieldRepository; +import com.iemr.common.repository.dynamic_form.FormRepository; +import com.iemr.common.repository.dynamic_form.ModuleRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.fasterxml.jackson.core.type.TypeReference; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Service +public class FormMasterServiceImpl implements FormMasterService { + + @Autowired + private ModuleRepository moduleRepo; + @Autowired private FormRepository formRepo; + @Autowired private FieldRepository fieldRepo; + + @Override + public FormModule createModule(ModuleDTO dto) { + FormModule module = new FormModule(); + module.setModuleName(dto.getModuleName()); + return moduleRepo.save(module); + } + + @Override + public FormDefinition createForm(FormDTO dto) { + FormModule module = moduleRepo.findById(dto.getModuleId()) + .orElseThrow(() -> new IllegalArgumentException("Invalid module ID")); + + FormDefinition form = new FormDefinition(); + form.setFormId(dto.getFormId()); + form.setFormName(dto.getFormName()); + form.setModule(module); + return formRepo.save(form); + } + + @Override + public List createField(List dtoList) { + List savedFields = new ArrayList<>(); + + for (FieldDTO dto : dtoList) { + FormDefinition form = formRepo.findByFormId(dto.getFormId()) + .orElseThrow(() -> new IllegalArgumentException("Invalid form ID")); + + FormField field = new FormField(); + field.setForm(form); + field.setSectionTitle(dto.getSectionTitle()); + field.setFieldId(dto.getFieldId()); + field.setLabel(dto.getLabel()); + field.setType(dto.getType()); + field.setIsVisible(dto.getIsVisible()); + field.setIsRequired(dto.getIsRequired()); + field.setDefaultValue(dto.getDefaultValue()); + field.setPlaceholder(dto.getPlaceholder()); + field.setOptions(dto.getOptions()); + field.setValidation(dto.getValidation()); + field.setConditional(dto.getConditional()); + field.setSequence(dto.getSequence()); + + savedFields.add(fieldRepo.save(field)); + } + + return savedFields; + } + + @Override + public FormField updateField(FieldDTO dto) { + FormField field = fieldRepo.findById(dto.getId()) + .orElseThrow(() -> new IllegalArgumentException("Field not found: " + dto.getId())); + field.setId(dto.getId()); + field.setSectionTitle(dto.getSectionTitle()); + field.setLabel(dto.getLabel()); + field.setType(dto.getType()); + field.setIsVisible(dto.getIsVisible()); + field.setIsRequired(dto.getIsRequired()); + field.setDefaultValue(dto.getDefaultValue()); + field.setPlaceholder(dto.getPlaceholder()); + field.setSequence(dto.getSequence()); + field.setOptions(dto.getOptions()); + field.setValidation(dto.getValidation()); + field.setConditional(dto.getConditional()); + + + return fieldRepo.save(field); + } + + @Override + public FormResponseDTO getStructuredFormByFormId(String formId) { + FormDefinition form = formRepo.findByFormId(formId) + .orElseThrow(() -> new IllegalArgumentException("Invalid form ID")); + + List fields = fieldRepo.findByForm_FormIdOrderBySequenceAsc(formId); + ObjectMapper objectMapper = new ObjectMapper(); + + List fieldDtos = fields.stream() + .map(field -> { + FieldResponseDTO dto = new FieldResponseDTO(); + dto.setId(field.getId()); + dto.setVisible(field.getIsVisible()); + dto.setFormId(field.getForm().getFormId()); + dto.setSectionTitle(field.getSectionTitle()); + dto.setFieldId(field.getFieldId()); + dto.setLabel(field.getLabel()); + dto.setType(field.getType()); + dto.setIsRequired(field.getIsRequired()); + dto.setDefaultValue(field.getDefaultValue()); + dto.setPlaceholder(field.getPlaceholder()); + dto.setSequence(field.getSequence()); + + try { + // Handle options + if (field.getOptions() != null && !field.getOptions().isBlank()) { + List options = objectMapper.readValue(field.getOptions(), new TypeReference<>() {}); + dto.setOptions(options.isEmpty() ? null : options); + } else { + dto.setOptions(null); + } + + // Handle validation + if (field.getValidation() != null && !field.getValidation().isBlank()) { + Map validation = objectMapper.readValue(field.getValidation(), new TypeReference<>() {}); + dto.setValidation(validation.isEmpty() ? null : validation); + } else { + dto.setValidation(null); + } + + // Handle conditional + if (field.getConditional() != null && !field.getConditional().isBlank()) { + Map conditional = objectMapper.readValue(field.getConditional(), new TypeReference<>() {}); + dto.setConditional(conditional.isEmpty() ? null : conditional); + } else { + dto.setConditional(null); + } + } catch (JsonProcessingException e) { + System.err.println("JSON Parsing Error in field: " + field.getFieldId()); + throw new RuntimeException("Failed to parse JSON for field: " + field.getFieldId(), e); + } + + return dto; + }) + .sorted(Comparator.comparing(FieldResponseDTO::getId)) + .collect(Collectors.toList()); + + + GroupedFieldResponseDTO singleSection = new GroupedFieldResponseDTO(); + singleSection.setSectionTitle("HBNC Form Fields"); // your custom section title + singleSection.setFields(fieldDtos); + + FormResponseDTO response = new FormResponseDTO(); + response.setVersion(form.getVersion()); + response.setFormId(form.getFormId()); + response.setFormName(form.getFormName()); + response.setSections(List.of(singleSection)); + + return response; + } + + + @Override + public void deleteField(Long fieldId) { + fieldRepo.deleteById(fieldId); + } + +} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/service/firebaseNotification/FirebaseNotificationService.java b/src/main/java/com/iemr/common/service/firebaseNotification/FirebaseNotificationService.java new file mode 100644 index 00000000..7f33c453 --- /dev/null +++ b/src/main/java/com/iemr/common/service/firebaseNotification/FirebaseNotificationService.java @@ -0,0 +1,118 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +* +/* +* AMRIT – Accessible Medical Records via Integrated Technology +*/ +package com.iemr.common.service.firebaseNotification; + +import com.google.firebase.FirebaseException; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; +import com.iemr.common.data.userToken.UserTokenData; +import com.iemr.common.model.notification.NotificationMessage; +import com.iemr.common.model.notification.UserToken; +import com.iemr.common.repo.userToken.UserTokenRepo; +import com.iemr.common.utils.CookieUtil; +import com.iemr.common.utils.JwtUtil; +import com.iemr.common.utils.exception.IEMRException; +import jakarta.servlet.http.HttpServletRequest; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.sql.Timestamp; +import java.util.Optional; + +@Service +public class FirebaseNotificationService { + final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired(required = false) + FirebaseMessaging firebaseMessaging; + + @Autowired + private UserTokenRepo userTokenRepo; + + @Autowired + private CookieUtil cookieUtil; + + @Autowired + private JwtUtil jwtUtil; + + private Message message; + + + public String sendNotification(NotificationMessage notificationMessage) { + if (firebaseMessaging == null) { + logger.error("⚠️ Firebase is not configured, skipping notification"); + return null; + } + + Notification notification = Notification.builder().setTitle(notificationMessage.getTitle()).setBody(notificationMessage.getBody()).build(); + + Message message = Message.builder().setTopic(notificationMessage.getToken()).setNotification(notification).putAllData(notificationMessage.getData()).build(); + + + try { + String response = FirebaseMessaging.getInstance().send(message); + + return response; + } catch (FirebaseException e) { + return "Error sending notification"; + + } + } + + public String updateToken(UserToken userToken) { + Optional existingTokenData = userTokenRepo.findById(userToken.getUserId()); + + UserTokenData userTokenData; + + if (existingTokenData.isPresent()) { + userTokenData = existingTokenData.get(); + userTokenData.setToken(userToken.getToken()); + userTokenData.setUpdatedAt(new Timestamp(System.currentTimeMillis())); + } else { + userTokenData = new UserTokenData(); + userTokenData.setUserId(userToken.getUserId()); + userTokenData.setToken(userToken.getToken()); + userTokenData.setUpdatedAt(new Timestamp(System.currentTimeMillis())); + } + + userTokenRepo.save(userTokenData); + return "Save Successfully"; + } + + public String getUserToken() throws IEMRException { + HttpServletRequest requestHeader = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()) + .getRequest(); + String jwtTokenFromCookie = cookieUtil.getJwtTokenFromCookie(requestHeader); + return userTokenRepo.findById(Integer.parseInt(jwtUtil.getUserIdFromToken(jwtTokenFromCookie))) // because your userId is Long in DB + .map(UserTokenData::getToken) + .orElse(null); // + } + +} diff --git a/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java b/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java index 7a24c6da..4297022a 100644 --- a/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java +++ b/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java @@ -1,8 +1,8 @@ /* -* AMRIT – Accessible Medical Records via Integrated Technology -* Integrated EHR (Electronic Health Records) Solution +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution * -* Copyright (C) "Piramal Swasthya Management and Research Institute" +* Copyright (C) "Piramal Swasthya Management and Research Institute" * * This file is part of AMRIT. * @@ -34,12 +34,14 @@ import java.util.Objects; import java.util.Set; +import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; // import javax.transaction.Transactional; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.DigestUtils; @@ -84,6 +86,9 @@ public void setSubCategoryRepository(SubCategoryRepository subCategoryRepository private InputMapper inputMapper = new InputMapper(); + @Value("${allowed.file.extensions}") + private String allowedFileExtensions; + @Override public String getKMFileLists(String request) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); @@ -125,49 +130,84 @@ public String addKMFile(String request) throws IOException, NoSuchAlgorithmExcep return kmFileManagers.toString(); } - + private ArrayList addKMFile(Iterable kmFileManagers) throws IOException, NoSuchAlgorithmException { ArrayList savedFileManagers = new ArrayList(); FileOutputStream newFile = null; FileInputStream fis = null; - try - { - for (KMFileManager kmFileManager : kmFileManagers) { - if (kmFileManager.getFileName() != null && kmFileManager.getProviderServiceMapID() != null - && kmFileManager.getFileContent() != null) { - kmFileManager.setFileName(kmFileManager.getFileName().replace("`", "").replace("'", "").replace("$", "") - .replace("\\", "").replace("/", "").replace("~", "").replace("`", "").replace("!", "") - .replace("@", "").replace("#", "").replace("$", "").replace("%", "").replace("^", "") - .replace("&", "").replace("*", "").replace("(", "").replace(")", "").replace("{", "") - .replace("}", "").replace("[", "").replace("]", "").replace("|", "").replace("\\", "") - .replace(":", "").replace(";", "").replace("-", "").replace("_", "").replace("+", "") - .replace("=", "").replace("\"", "").replace("'", "")); - String tempFilePath = ConfigProperties.getPropertyByName("tempFilePath"); - newFile = new FileOutputStream(tempFilePath + "/" + kmFileManager.getFileName()); - newFile.write(Base64.getDecoder().decode(kmFileManager.getFileContent())); - newFile.flush(); - newFile.close(); - fis = new FileInputStream(tempFilePath + "/" + kmFileManager.getFileName()); - String checksum = DigestUtils.md5DigestAsHex(fis); - fis.close(); - logger.info("File is " + kmFileManager.getFileName()); - logger.info("File size is " + new File(tempFilePath + "/" + kmFileManager.getFileName()).length()); - logger.info("File checksum is " + checksum); - logger.info("File checksum length is " + checksum.length()); - kmFileManager.setFileCheckSum(checksum); - kmFileManager.setKmUploadStatus(KM_UPLOADSTATUS_PENDING); - String version = getFileVersion(kmFileManager); - kmFileManager.setVersionNo(version); - String documentPath = kmFileManager.getProviderServiceMapID() + "/"; - if (kmFileManager.getCategoryID() != null) { - documentPath += kmFileManager.getCategoryID() + "/"; - } - if (kmFileManager.getSubCategoryID() != null) { - documentPath += kmFileManager.getSubCategoryID() + "/"; - } - if (kmFileManager.getVanID() != null) - documentPath += kmFileManager.getVanID() + "/"; + try { + for (KMFileManager kmFileManager : kmFileManagers) { + if (kmFileManager.getFileName() != null && kmFileManager.getProviderServiceMapID() != null + && kmFileManager.getFileContent() != null) { + + if (allowedFileExtensions == null || allowedFileExtensions.trim().isEmpty()) { + throw new IllegalStateException( + "Environment variable 'allowed.file.extensions' is not configured or is empty"); + } + List allowedExtensions = Arrays.asList(allowedFileExtensions.split(",")); + logger.info("Allowed extensions: " + allowedExtensions); + + + // Extract extension from fileName + String extensionFromName = FilenameUtils.getExtension(kmFileManager.getFileName()); + logger.info("extensionFromName " + extensionFromName); + + // Normalize payload fileExtension (remove dot if present) + String extensionFromPayload = kmFileManager.getFileExtension(); + logger.info("extensionPayload " + extensionFromPayload); + + if (extensionFromPayload != null && extensionFromPayload.startsWith(".")) { + extensionFromPayload = extensionFromPayload.substring(1); + } + + // Validate extensions + if (extensionFromName == null || extensionFromPayload == null) { + throw new IOException("File extension missing"); + } + + if (!extensionFromName.equalsIgnoreCase(extensionFromPayload)) { + throw new IOException( + "File extension mismatch: " + extensionFromName + " vs " + extensionFromPayload); + } + + if (!allowedExtensions.contains(extensionFromName.toLowerCase())) { + throw new IOException("File extension not allowed: " + extensionFromName); + } + + kmFileManager.setFileName(kmFileManager.getFileName().replace("`", "").replace("'", "") + .replace("$", "") + .replace("\\", "").replace("/", "").replace("~", "").replace("`", "").replace("!", "") + .replace("@", "").replace("#", "").replace("$", "").replace("%", "").replace("^", "") + .replace("&", "").replace("*", "").replace("(", "").replace(")", "").replace("{", "") + .replace("}", "").replace("[", "").replace("]", "").replace("|", "").replace("\\", "") + .replace(":", "").replace(";", "").replace("-", "").replace("_", "").replace("+", "") + .replace("=", "").replace("\"", "").replace("'", "")); + String tempFilePath = ConfigProperties.getPropertyByName("tempFilePath"); + newFile = new FileOutputStream(tempFilePath + "/" + kmFileManager.getFileName()); + newFile.write(Base64.getDecoder().decode(kmFileManager.getFileContent())); + newFile.flush(); + newFile.close(); + fis = new FileInputStream(tempFilePath + "/" + kmFileManager.getFileName()); + String checksum = DigestUtils.md5DigestAsHex(fis); + fis.close(); + logger.info("File is " + kmFileManager.getFileName()); + logger.info("File size is " + new File(tempFilePath + "/" + kmFileManager.getFileName()).length()); + logger.info("File checksum is " + checksum); + logger.info("File checksum length is " + checksum.length()); + kmFileManager.setFileCheckSum(checksum); + kmFileManager.setKmUploadStatus(KM_UPLOADSTATUS_PENDING); + String version = getFileVersion(kmFileManager); + kmFileManager.setVersionNo(version); + String documentPath = kmFileManager.getProviderServiceMapID() + "/"; + if (kmFileManager.getCategoryID() != null) { + documentPath += kmFileManager.getCategoryID() + "/"; + } + if (kmFileManager.getSubCategoryID() != null) { + documentPath += kmFileManager.getSubCategoryID() + "/"; + } + if (kmFileManager.getVanID() != null) + documentPath += kmFileManager.getVanID() + "/"; documentPath += version + "/"; documentPath += kmFileManager.getFileName(); @@ -176,9 +216,9 @@ private ArrayList addKMFile(Iterable kmFileManager if (uuid != null) { kmFileManager.setKmUploadStatus(KM_UPLOADSTATUS_COMPLETED); kmFileManager.setFileUID(uuid); - + kmFileManager.setSubCategoryID(kmFileManager.getSubCategoryID()); - + savedFileManagers.add(kmFileManagerRepository.save(kmFileManager)); if (kmFileManager.getSubCategoryID() != null) { updateSubcategoryFilePath(kmFileManager); @@ -194,7 +234,7 @@ private ArrayList addKMFile(Iterable kmFileManager finally { if(newFile !=null) - newFile.close(); + newFile.close(); if(fis !=null) fis.close(); } @@ -211,7 +251,7 @@ private String getFileVersion(KMFileManager kmFileManager) { List files = kmFileManagerRepository.getKMFileByFileName(kmFileManager.getProviderServiceMapID(), kmFileManager.getFileName()); version = "V" + (files.size() + 1); - + return version; } } diff --git a/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java b/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java index 89e238c0..d7dc6e2e 100644 --- a/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java +++ b/src/main/java/com/iemr/common/service/users/IEMRAdminUserService.java @@ -121,6 +121,8 @@ public List getUserServiceRoleMappingForProvider(Integ List getUserServiceRoleMapping(Long userID) throws IEMRException; + List getUserIdbyUserName(String userName) throws IEMRException; + } diff --git a/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java b/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java index 05854843..44bd2247 100644 --- a/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java +++ b/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java @@ -1218,4 +1218,10 @@ public User getUserById(Long userId) throws IEMRException { throw new IEMRException("Error fetching user with ID: " + userId, e); } } + + @Override + public List getUserIdbyUserName(String userName) { + + return iEMRUserRepositoryCustom.findByUserName(userName); + } } diff --git a/src/main/java/com/iemr/common/service/welcomeSms/WelcomeBenificarySmsService.java b/src/main/java/com/iemr/common/service/welcomeSms/WelcomeBenificarySmsService.java new file mode 100644 index 00000000..9a0eeed6 --- /dev/null +++ b/src/main/java/com/iemr/common/service/welcomeSms/WelcomeBenificarySmsService.java @@ -0,0 +1,9 @@ +package com.iemr.common.service.welcomeSms; + +import org.springframework.stereotype.Service; + +@Service +public interface WelcomeBenificarySmsService { + public String sendWelcomeSMStoBenificiary(String contactNo,String beneficiaryName,String beneficiaryId); + +} diff --git a/src/main/java/com/iemr/common/service/welcomeSms/WelcomeBenificarySmsServiceImpl.java b/src/main/java/com/iemr/common/service/welcomeSms/WelcomeBenificarySmsServiceImpl.java new file mode 100644 index 00000000..67b642ab --- /dev/null +++ b/src/main/java/com/iemr/common/service/welcomeSms/WelcomeBenificarySmsServiceImpl.java @@ -0,0 +1,103 @@ +package com.iemr.common.service.welcomeSms; + +import com.google.common.cache.LoadingCache; +import com.iemr.common.data.sms.SMSTemplate; +import com.iemr.common.repository.sms.SMSTemplateRepository; +import com.iemr.common.repository.sms.SMSTypeRepository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +@Service +public class WelcomeBenificarySmsServiceImpl implements WelcomeBenificarySmsService { + final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + @Value("${sms-username}") + private String smsUserName; + + @Value("${sms-password}") + private String smsPassword; + + @Value("${sms-entityid}") + private String smsEntityId; + + @Value("${sms-consent-source-address}") + private String smsSourceAddress; + + @Value("${send-message-url}") + private String SMS_GATEWAY_URL; + + @Autowired + SMSTemplateRepository smsTemplateRepository; + + @Autowired + SMSTypeRepository smsTypeRepository; + + private String smsTemplateName = "welcome_sms"; + + private String smsTemplate; + + @Override + public String sendWelcomeSMStoBenificiary(String contactNo, String beneficiaryName, String beneficiaryId) { + final RestTemplate restTemplate = new RestTemplate(); + + Optional smsTemplateData = smsTemplateRepository.findBySmsTemplateName(smsTemplateName); + if (smsTemplateData.isPresent()) { + smsTemplate = smsTemplateRepository.findBySmsTemplateID(smsTemplateData.get().getSmsTemplateID()).getSmsTemplate(); + + } + + logger.info("sms template" + smsTemplate); + + + String sendSMSAPI = SMS_GATEWAY_URL; + + try { + + String message = smsTemplate.replace("$$BENE_NAME$$", beneficiaryName).replace("$$BEN_ID$$", beneficiaryId); + // Build payload + Map payload = new HashMap<>(); + payload.put("customerId", smsUserName); + payload.put("destinationAddress", contactNo); + payload.put("message", message); + payload.put("sourceAddress", smsSourceAddress); + payload.put("messageType", "SERVICE_IMPLICIT"); + payload.put("dltTemplateId", smsTemplateData.get().getDltTemplateId()); + payload.put("entityId", smsEntityId); + // Set headers + HttpHeaders headers = new HttpHeaders(); + String auth = smsUserName + ":" + smsPassword; + headers.add("Authorization", + "Basic " + Base64.getEncoder().encodeToString(auth.getBytes())); + + headers.setContentType(MediaType.APPLICATION_JSON); + logger.info("payload: " + payload); + HttpEntity> request = new HttpEntity<>(payload, headers); + + // Call API + ResponseEntity response = restTemplate.postForEntity(sendSMSAPI, request, String.class); + logger.info("sms-response:" + response.getBody()); + if (response.getStatusCode().value() == 200) { + return "OTP sent successfully on register mobile number"; + } else { + return "Fail"; + + } + + } catch (Exception e) { + return "Error sending SMS: " + e.getMessage().toString(); + } + + } +} diff --git a/src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java index 13eaea2f..16466ee5 100644 --- a/src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/common/utils/JwtUserIdValidationFilter.java @@ -169,7 +169,8 @@ private boolean shouldSkipAuthentication(String path, String contextPath) { || path.startsWith(contextPath + "/user/saveUserSecurityQuesAns") || path.startsWith(contextPath + "/user/userLogout") || path.startsWith(contextPath + "/user/validateSecurityQuestionAndAnswer") - || path.startsWith(contextPath + "/user/logOutUserFromConcurrentSession"); + || path.startsWith(contextPath + "/user/logOutUserFromConcurrentSession") + || path.startsWith(contextPath + "/user/refreshToken"); } private String getJwtTokenFromCookies(HttpServletRequest request) { diff --git a/src/main/java/com/iemr/common/utils/JwtUtil.java b/src/main/java/com/iemr/common/utils/JwtUtil.java index dc29018c..d8414968 100644 --- a/src/main/java/com/iemr/common/utils/JwtUtil.java +++ b/src/main/java/com/iemr/common/utils/JwtUtil.java @@ -23,9 +23,9 @@ public class JwtUtil { @Value("${jwt.refresh.expiration}") private long REFRESH_EXPIRATION_TIME; - + @Autowired - private TokenDenylist tokenDenylist; + private TokenDenylist tokenDenylist; private SecretKey getSigningKey() { if (SECRET_KEY == null || SECRET_KEY.isEmpty()) { @@ -86,12 +86,12 @@ public Claims validateToken(String token) { try { Claims claims = Jwts.parser().verifyWith(getSigningKey()).build().parseSignedClaims(token).getPayload(); String jti = claims.getId(); - + // Check if token is denylisted (only if jti exists) if (jti != null && tokenDenylist.isTokenDenylisted(jti)) { return null; } - + return claims; } catch (ExpiredJwtException ex) { diff --git a/src/main/java/com/iemr/common/utils/exception/GlobalExceptionHandler.java b/src/main/java/com/iemr/common/utils/exception/GlobalExceptionHandler.java new file mode 100644 index 00000000..632e90d2 --- /dev/null +++ b/src/main/java/com/iemr/common/utils/exception/GlobalExceptionHandler.java @@ -0,0 +1,35 @@ +package com.iemr.common.utils.exception; + +import com.iemr.common.utils.response.ApiResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.stream.Collectors; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(Exception.class) + public ResponseEntity> handleException(Exception ex) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ApiResponse.error("Something went wrong", HttpStatus.INTERNAL_SERVER_ERROR.value(),null)); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity> handleValidationException(MethodArgumentNotValidException ex) { + String errorMessage = ex.getBindingResult().getFieldErrors().stream() + .map(error -> error.getField() + ": " + error.getDefaultMessage()) + .collect(Collectors.joining(", ")); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ApiResponse.error("Validation Error: " + errorMessage, HttpStatus.BAD_REQUEST.value(),null)); + } + + @ExceptionHandler(IllegalArgumentException.class) + public ResponseEntity> handleIllegalArgException(IllegalArgumentException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(ApiResponse.error(ex.getMessage(), HttpStatus.BAD_REQUEST.value(),null)); + } +} diff --git a/src/main/java/com/iemr/common/utils/http/HTTPRequestInterceptor.java b/src/main/java/com/iemr/common/utils/http/HTTPRequestInterceptor.java index 23b0af62..1c322dc4 100644 --- a/src/main/java/com/iemr/common/utils/http/HTTPRequestInterceptor.java +++ b/src/main/java/com/iemr/common/utils/http/HTTPRequestInterceptor.java @@ -21,7 +21,7 @@ */ package com.iemr.common.utils.http; - +import java.nio.charset.StandardCharsets; import javax.ws.rs.core.MediaType; import org.slf4j.Logger; @@ -32,10 +32,10 @@ import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; -import com.iemr.common.utils.response.OutputResponse; import com.iemr.common.utils.sessionobject.SessionObject; import com.iemr.common.utils.validator.Validator; +import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @Configuration @@ -125,12 +125,30 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons break; } } catch (Exception e) { - OutputResponse output = new OutputResponse(); - output.setError(e); - response.getOutputStream().print(output.toString()); - response.setContentType(MediaType.APPLICATION_JSON); - response.setContentLength(output.toString().length()); - response.setHeader("Access-Control-Allow-Origin", "*"); + logger.error("Authorization failed: {}", e.getMessage(), e); + + String errorMessage = e.getMessage(); + if (errorMessage == null || errorMessage.trim().isEmpty()) { + errorMessage = "Unauthorized access or session expired."; + } + + String jsonErrorResponse = "{" + + "\"status\": \"Unauthorized\"," + + "\"statusCode\": 401," + + "\"errorMessage\": \"" + errorMessage.replace("\"", "\\\"") + "\"" + + "}"; + + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 401 + response.setContentType(MediaType.APPLICATION_JSON); + response.setHeader("Access-Control-Allow-Origin", "*"); + + // Better to use getBytes().length for accurate byte size + byte[] responseBytes = jsonErrorResponse.getBytes(StandardCharsets.UTF_8); + response.setContentLength(responseBytes.length); + + ServletOutputStream out = response.getOutputStream(); + out.write(responseBytes); + out.flush(); status = false; } } @@ -164,4 +182,4 @@ public void afterCompletion(HttpServletRequest request, HttpServletResponse resp throws Exception { logger.debug("In afterCompletion Request Completed"); } -} \ No newline at end of file +} diff --git a/src/main/java/com/iemr/common/utils/response/ApiResponse.java b/src/main/java/com/iemr/common/utils/response/ApiResponse.java new file mode 100644 index 00000000..928a2a25 --- /dev/null +++ b/src/main/java/com/iemr/common/utils/response/ApiResponse.java @@ -0,0 +1,31 @@ +package com.iemr.common.utils.response; + +import lombok.Data; + +@Data +public class ApiResponse { + private boolean success; + private String message; + private Integer statusCode; + + private T data; + + public ApiResponse() {} + + public ApiResponse(boolean success, String message, Integer statusCode,T data) { + this.success = success; + this.message = message; + this.data = data; + this.statusCode = statusCode; + } + + public static ApiResponse success(String message,Integer statusCode, T data) { + return new ApiResponse<>(true, message,statusCode, data); + } + + public static ApiResponse error(String message,Integer statusCode, T data) { + return new ApiResponse<>(false, message, statusCode,data); + } + + // getters and setters +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 813637b0..62fb2215 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -173,3 +173,214 @@ failedLoginAttempt=5 jwt.access.expiration=86400000 jwt.refresh.expiration=604800000 +# local env + + + + +## KM Configuration +km-base-protocol=http +km-username=okmAdmin +km-password=admin +km-base-url=http://localhost:8084/OpenKM +km-base-path=localhost:8084/OpenKM +km-root-path=/okm:personal/users/ +km-guest-user=guest +km-guest-password=guest + +# CTI Config +cti-server-ip=10.208.122.99 +cti-logger_base_url=http://10.208.122.99/logger +sms-gateway-url = + +# Identity Config +identity-api-url = http://localhost:8094/ +#Verify whether 1097 and identity are same? +identity-1097-api-url = http://localhost:8095/ +##Generate Benificiary Config +genben-api=http://localhost:8092/ + +#### SMS Configuration +send-sms=false +sendSMSUrl = http://localhost:8080/sms/sendSMS +source-address=AIDSHL +sms-username= +sms-password= +send-message-url= + +###SMS Scheduler configurations +start-sms-scheduler=false +cron-scheduler-sms=0 0/1 * * * ? * + +#### Email Configuration +send-email=false +spring.mail.host=smtp.gmail.com +spring.mail.port=587 +spring.mail.username= +spring.mail.password= +spring.mail.properties.mail.smtp.auth=true +spring.mail.properties.mail.smtp.starttls.enable=true + +###Email Scheduler configurations +start-email-scheduler=true +cron-scheduler-email=0 0/1 * * * ? * + +##-------------------------------###cti data sync Scheduler configurations------------------------------------------------------ + +start-ctidatasync-scheduler=false +cron-scheduler-ctidatasync=0 0 2 */2 * ? + +##-------------------------------###cti data check with call detail report Scheduler------------------------------------------------------ + +#Runs at everyday 12:10AM +start-ctidatacheck-scheduler=true +cron-scheduler-ctidatacheck=0 10 00 * * * + +##---------------------------------#### Registration schedular for Avni------------------------------------------------------------------------------ + +start-avni-scheduler=false +cron-avni-registration=0 0/1 * * * ? * + +##------------------------------------------------#### Everwell Regsitration Scheduler--------------------------------------------------------------- + +start-registration-scheduler=false +cron-scheduler-registration=0 34 19 * * ? * + +##----------------------------------------------------#everwell data sync----------------------------------------------------------- + +start-everwelldatasync-scheduler=false +cron-scheduler-everwelldatasync=0 0/5 * * * ? * + +##-----------------------------------------------#NHM data dashboard schedular---------------------------------------------------------------- +# run at everyday 12:01AM +start-nhmdashboard-scheduler=true +cron-scheduler-nhmdashboard=0 1 * * * ? * +##----------------------------------------------------#grievance data sync----------------------------------------------------------- + +cron-scheduler-grievancedatasync=0 0/2 * * * ? + +### Redis IP +spring.redis.host=localhost + +##--------------------------------------------------------------------------------------------------------------- +###CTI data sync schedular +cz-duration=40 +##--------------------------------------------------------------------------------------------------------------- +## prescription template +TMprescriptionTemplate=TMPrescription +##--------------------------------------------------------------------------------------------------------------- +##duration for everwell calender +everwellCalendarDuration=15 +##--------------------------------------------------------------------------------------------------------------- +##lonic variables +lonicPageSize=10 +##--------------------------------------------------------------------------------------------------------------- +#snomedcti +snomedCTPageSize=10 +##--------------------------------------------------------------------------------------------------------------- +#call retry count +callRetryConfiguration=3 +##--------------------------------------------------------------------------------------------------------------- +#avni registration Duration +avniRegistrationLimit=7 + +#--------------------------NHM Agent Real Time Data---------------------------- +nhm.agent.real.time.data.url= http://175.101.1.83/apps/utility/alive_api.php +nhm.agent.real.time.data.cron.scheduler=0 */2 * ? * * +nhm.agent.real.time.data.cron.flag=true + +carestream_socket_ip = 192.168.43.39 +carestream_socket_port = 1235 + +## everwell variables +everwellUserName = +everwellPassword = +amritUserName = +amritPassword = + +## everwell API call +everwellAddSupportAction = https://beta-hub.everwell.org/Api/Patients/AddSupportAction +everwellEditDoses = https://beta-hub.everwell.org/Api/Patients/EditManualDoses +everwellEditMissedDoses = https://beta-hub.everwell.org/Api/Patients/EditMissedDoses +everwellGetPatientAdherenceUrl = https://beta-hub.everwell.org/Api/Patients/CurrentMonthMissedAdherence?Page= +everwellEditSecondaryPhoneNo = https://beta-hub.everwell.org/Api/Patients/EditPhoneNumber +everwell1097userAuthenticate = http://localhost:8083/user/userAuthenticate +everwelluserAuthenticate = https://beta-hub.everwell.org/token +everwellRegisterBenficiary = http://localhost:8083/beneficiary/create + + +## LungAssessment credentials +lungAssessmentEmail = +lungAssessmentPassword = + + +## SWASSA APIs +lungAssessmentAdminLogin = http://swaasa.sandbox.swaasa.ai/api/adminLogin +lungAssessmentValidateCough = http://swaasa.sandbox.swaasa.ai/api/verifycough +lungAssessmentStartAssesment = http://swaasa.sandbox.swaasa.ai/api/assessment +lungAssessmentGetAssesment = http://swaasa.sandbox.swaasa.ai/api/getAssessment + +#E- Sanjeevani user authenticate creds +eSanjeevani.url: https://preprod.esanjeevaniopd.xyz/uat/aus/api/ThirdPartyAuth/providerLogin +eSanjeevani.userName: +eSanjeevani.password: +eSanjeevani.salt: 123456 +eSanjeevani.source: 11001 +eSanjeevani.registerPatient: https://preprod.esanjeevaniopd.xyz/uat/ps/api/v1/Patient +eSanjeevani.routeUrl: https://uat.esanjeevani.in/user/signin + +biometric.discover.url = http://127.0.0.1:port/ +biometric.deviceInfo.url = http://127.0.0.1:port/rd/info +biometric.capture.url = http://127.0.0.1:port/rd/capture +eAusadhaUrl=https://dlc.kar.nic.in/e-services/api/DWInstituteInward + +eausadhaAuthorization= +spring.main.allow-bean-definition-overriding=true +spring.main.allow-circular-references=true + +fileBasePath =/Doc +##grievance API call +updateGrievanceDetails = /grsbepro/igemr1097/public/api/v1/state-wise/grievance-list?page=PageNumber¤tpage=1 +updateGrievanceTransactionDetails=/grsbepro/igemr1097/public/api/v1/grievance_details/ + +## grievance variables +grievanceUserName = +grievancePassword = + +grievanceUserAuthenticate = +grievanceDataSyncDuration = + +springdoc.api-docs.enabled=true +springdoc.swagger-ui.enabled=true + +isProduction=false +grievanceAllocationRetryConfiguration=3 + +logging.path=logs/ +logging.file.name=logs/common-api.log + +captcha.secret-key= +captcha.verify-url= https://challenges.cloudflare.com/turnstile/v0/siteverify +captcha.enable-captcha=false + +cors.allowed-origins= http://localhost:*,https://amritdemo.piramalswasthya.org + +# DB Connections +spring.datasource.url=jdbc:mysql://localhost:3306/db_iemr +spring.datasource.username= +spring.datasource.password= + + +secondary.datasource.username= +secondary.datasource.password= +secondary.datasource.url=jdbc:mysql://localhost:3306/db_reporting +secondary.datasource.driver-class-name=com.mysql.jdbc.Driver + +video-call-url = + +allowed.file.extensions=msg,pdf,png,jpeg,doc,docx,xlsx,xls,csv,txt + +##sms details for beneficiary otp cosent +sms-template-name = otp_consent + +