From 0df3ef6959891ba02760f16cf4d9c34c48837892 Mon Sep 17 00:00:00 2001 From: Sachin Kadam <152252767+sac2kadam@users.noreply.github.com> Date: Tue, 24 Jun 2025 12:09:39 +0530 Subject: [PATCH 01/16] cti data chek nhm schedular --- src/main/environment/common_ci.properties | 12 ++++++++---- src/main/environment/common_docker.properties | 11 ++++++++--- src/main/environment/common_example.properties | 6 +++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 8d42a126..91039c66 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -54,10 +54,14 @@ start-email-scheduler=true cron-scheduler-email=0 0/1 * * * ? * ###cti data check with call detail report Scheduler -#Runs at everyday 12:10AM -start-ctidatacheck-scheduler=true -cron-scheduler-ctidatacheck=0 10 00 * * * - +start-ctidatacheck-scheduler=@env.START_CTIDATACHECK_SCHEDULER@ +cron-scheduler-ctidatacheck=0 00 02 * * * +##-------------------------------###cti data sync Scheduler configurations------------------------------------------------------ +start-ctidatasync-scheduler=@env.START_CTIDATASYNC_SCHEDULER@ +cron-scheduler-ctidatasync=0 30 01 * * ? * +##-----------------------------------------------#NHM data dashboard schedular---------------------------------------------------------------- +start-nhmdashboard-scheduler=@env.START_NHMDASHBOARD_SCHEDULER@ +cron-scheduler-nhmdashboard=0 30 0 * * ? * ### generate Beneficiary Config genben-api= @env.BEN_GEN_API_URL@ diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index 6799c959..d506dded 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -55,9 +55,14 @@ cron-scheduler-email=0 0/1 * * * ? * ###cti data check with call detail report Scheduler #Runs at everyday 12:10AM -start-ctidatacheck-scheduler=true -cron-scheduler-ctidatacheck=0 10 00 * * * - +start-ctidatacheck-scheduler=${START_CTIDATACHECK_SCHEDULER} +cron-scheduler-ctidatacheck=0 00 02 * * * +##-------------------------------###cti data sync Scheduler configurations------------------------------------------------------ +start-ctidatasync-scheduler=${START_CTIDATASYNC_SCHEDULER} +cron-scheduler-ctidatasync=0 30 01 * * ? * +##-----------------------------------------------#NHM data dashboard schedular---------------------------------------------------------------- +start-nhmdashboard-scheduler=${START_NHMDASHBOARD_SCHEDULER} +cron-scheduler-nhmdashboard=0 30 0 * * ? * ### generate Beneficiary Config genben-api= ${BEN_GEN_API_URL} diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 7bc96104..20ab6f04 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -64,13 +64,13 @@ cron-scheduler-email=0 0/1 * * * ? * ##-------------------------------###cti data sync Scheduler configurations------------------------------------------------------ start-ctidatasync-scheduler=false -cron-scheduler-ctidatasync=0 0 2 */2 * ? +cron-scheduler-ctidatasync=0 30 01 * * ? * ##-------------------------------###cti data check with call detail report Scheduler------------------------------------------------------ #Runs at everyday 12:10AM -start-ctidatacheck-scheduler=true -cron-scheduler-ctidatacheck=0 10 00 * * * +start-ctidatacheck-scheduler=false +cron-scheduler-ctidatacheck=0 00 02 * * * ##---------------------------------#### Registration schedular for Avni------------------------------------------------------------------------------ From 139c9339bdcb283b23e913b0fde01cea7d58d7ed Mon Sep 17 00:00:00 2001 From: Vanitha S <116701245+vanitha1822@users.noreply.github.com> Date: Tue, 24 Jun 2025 13:25:31 +0530 Subject: [PATCH 02/16] Add ? to the url and value to fetch values from env (#236) * (fix):Add ? to the url and value to fetch values from env * Change the variable to store the url --- src/main/environment/common_example.properties | 2 +- .../common/service/videocall/VideoCallServiceImpl.java | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 7bc96104..78e6bb57 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -198,7 +198,7 @@ grievanceAllocationRetryConfiguration=3 logging.path=logs/ logging.file.name=logs/common-api.log -video-call-url=https://vc.piramalswasthya.org/ +video-call-url=https://vc.piramalswasthya.org/? jibri.output.path=/srv/jibri/recordings video.recording.path=/srv/recordings diff --git a/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java b/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java index 6806834d..e6e0227a 100644 --- a/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java +++ b/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java @@ -33,12 +33,14 @@ public class VideoCallServiceImpl implements VideoCallService { @Autowired private VideoCallMapper videoCallMapper; - @Value("${video-call-url}") private String meetingLink; private boolean isLinkSent = false; private String consultationStatus = "Not Initiated"; + + @Value("${video-call-url}") private String jitsiLink; + public VideoCallServiceImpl() { // this.jitsiLink = ConfigProperties.getPropertyByName("video-call-url"); // logger.info("Jitsi Link fetched: " + this.jitsiLink); @@ -46,7 +48,8 @@ public VideoCallServiceImpl() { @Override public String generateMeetingLink() { - meetingLink=jitsiLink+RandomStringUtils.randomAlphanumeric(8); + logger.info("Jitsi Link: " + jitsiLink); + meetingLink=jitsiLink+"m="+RandomStringUtils.randomAlphanumeric(8); logger.info("Meeting link: " + meetingLink); return meetingLink; } From 95399d51ae594ab293aec81c4dbe01b940dcb95f Mon Sep 17 00:00:00 2001 From: Vanitha S <116701245+vanitha1822@users.noreply.github.com> Date: Tue, 24 Jun 2025 17:30:16 +0530 Subject: [PATCH 03/16] Update the response format for video link (#238) * (fix):Add ? to the url and value to fetch values from env * Change the variable to store the url * (fix):Json parsing for response --- .../common/controller/sms/SMSController.java | 8 +++++- .../common/service/sms/SMSServiceImpl.java | 26 +++++++++---------- .../videocall/VideoCallServiceImpl.java | 5 +++- 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/iemr/common/controller/sms/SMSController.java b/src/main/java/com/iemr/common/controller/sms/SMSController.java index 78a42793..ee985947 100644 --- a/src/main/java/com/iemr/common/controller/sms/SMSController.java +++ b/src/main/java/com/iemr/common/controller/sms/SMSController.java @@ -207,7 +207,13 @@ public String sendSMS( } logger.debug("sendSMS sending response " + response); logger.info("sendSMS sending response"); - return response.toString(); + String respStr = response.toString(); + respStr = respStr.replace("\\u003d", "=") + .replace("\\u003c", "<") + .replace("\\u003e", ">") + .replace("\\u0026", "&"); + return respStr; + } } diff --git a/src/main/java/com/iemr/common/service/sms/SMSServiceImpl.java b/src/main/java/com/iemr/common/service/sms/SMSServiceImpl.java index ad9345a1..022fd1f8 100644 --- a/src/main/java/com/iemr/common/service/sms/SMSServiceImpl.java +++ b/src/main/java/com/iemr/common/service/sms/SMSServiceImpl.java @@ -194,15 +194,15 @@ public String getSMSTemplates(SMSRequest smsRequest) throws Exception { @Override public String updateSMSTemplate(UpdateSMSRequest smsRequest) throws Exception { - SMSTemplate smsTemplate = null; - SMSTemplate request = smsMapper.updateRequestToSMSTemplate(smsRequest); - int updateCount = smsTemplateRepository.updateSMSTemplate(request.getSmsTemplateID(), request.getDeleted()); - if (updateCount > 0) { - smsTemplate = smsTemplateRepository.findBySmsTemplateID(request.getSmsTemplateID()); - } else { - throw new Exception("Failed to update the result"); - } - return OutputMapper.gsonWithoutExposeRestriction().toJson(smsMapper.smsTemplateToResponse(smsTemplate)); + SMSTemplate smsTemplate = null; + SMSTemplate request = smsMapper.updateRequestToSMSTemplate(smsRequest); + int updateCount = smsTemplateRepository.updateSMSTemplate(request.getSmsTemplateID(), request.getDeleted()); + if (updateCount > 0) { + smsTemplate = smsTemplateRepository.findBySmsTemplateID(request.getSmsTemplateID()); + } else { + throw new Exception("Failed to update the result"); + } + return OutputMapper.gsonWithoutExposeRestriction().toJson(smsMapper.smsTemplateToResponse(smsTemplate)); } @Override @@ -347,9 +347,8 @@ public SMSNotification prepareVideoCallSMS(SMSRequest request, VideoCallParamete sms.setPhoneNo(request.getFacilityPhoneNo()); } } - sms.setSms(smsToSend); - return smsNotification.save(sms); + return smsNotification.save(sms); } @@ -357,8 +356,8 @@ public String getVideoCallData(String methodName, VideoCallParameters videoCall) String variableValue = ""; switch (methodName.toLowerCase()) { case "videoconsultationlink": - variableValue = videoCall.getMeetingLink() != null ? videoCall.getMeetingLink() : ""; - break; + variableValue = videoCall.getMeetingLink() != null ? videoCall.getMeetingLink() : ""; + break; case "consultationdate": if (videoCall.getDateOfCall() != null) { SimpleDateFormat inputFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @@ -377,7 +376,6 @@ public String getVideoCallData(String methodName, VideoCallParameters videoCall) variableValue = result != null ? result.toString() : ""; break; } - return variableValue.trim(); } diff --git a/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java b/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java index e6e0227a..9db1a771 100644 --- a/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java +++ b/src/main/java/com/iemr/common/service/videocall/VideoCallServiceImpl.java @@ -75,7 +75,10 @@ public String sendMeetingLink(VideoCallRequest request) throws Exception { response.setResponse(responseData.toJson()); return OutputMapper.gsonWithoutExposeRestriction() - .toJson(response); + .toJson(response) .replace("\\u003d", "=") + .replace("\\u003c", "<") + .replace("\\u003e", ">") + .replace("\\u0026", "&"); } @Override From 57354a658fac0a33682b6497cba2e0d363194b67 Mon Sep 17 00:00:00 2001 From: Sachin Kadam <152252767+sac2kadam@users.noreply.github.com> Date: Fri, 27 Jun 2025 11:32:03 +0530 Subject: [PATCH 04/16] grievance scheduler added --- src/main/environment/common_ci.properties | 2 +- src/main/environment/common_docker.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 91039c66..a5e66660 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -174,7 +174,7 @@ springdoc.swagger-ui.enabled=false isProduction=@env.IS_PRODUCTION@ grievanceAllocationRetryConfiguration=3 -start-grievancedatasync-scheduler=true +start-grievancedatasync-scheduler=@env.START_GRIEVANCEDATASYNC_SCHEDULER@ cron-scheduler-grievancedatasync=0 0/2 * * * ? captcha.secret-key=@env.CAPTCHA_SECRET_KEY@ diff --git a/src/main/environment/common_docker.properties b/src/main/environment/common_docker.properties index d506dded..41881886 100644 --- a/src/main/environment/common_docker.properties +++ b/src/main/environment/common_docker.properties @@ -176,7 +176,7 @@ springdoc.swagger-ui.enabled=false isProduction=${IS_PRODUCTION} grievanceAllocationRetryConfiguration=3 -start-grievancedatasync-scheduler=false +start-grievancedatasync-scheduler=${START_GRIEVANCEDATASYNC_SCHEDULER} cron-scheduler-grievancedatasync=0 0/2 * * * ? captcha.secret-key=${CAPTCHA_SECRET_KEY} From 95be768c73f796bc20170b93060e18e061da732a Mon Sep 17 00:00:00 2001 From: SR20290919 Date: Fri, 27 Jun 2025 16:54:41 +0530 Subject: [PATCH 05/16] linking of subcategory to multiple files --- .../data/kmfilemanager/KMFileManager.java | 6 +- .../KMFileManagerRepository.java | 4 + .../KMFileManagerServiceImpl.java | 76 ++++++++++++++++++ .../service/services/CommonServiceImpl.java | 77 ++++++++++++++----- 4 files changed, 143 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java b/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java index 6630f367..6409837f 100644 --- a/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java +++ b/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java @@ -110,7 +110,11 @@ public class KMFileManager { @Transient @Expose private Integer categoryID; - @Transient +// @Transient +// @Expose +// private Integer subCategoryID; + + @Column(name = "SubCategoryID") // 🔴 DB-mapped field to associate files with a subcategory @Expose private Integer subCategoryID; @Transient diff --git a/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java b/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java index aad6a98f..615c841b 100644 --- a/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java +++ b/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java @@ -74,5 +74,9 @@ ArrayList getKMFileLists(@Param("providerServiceMapID") Integer p @Query("select kmFileManager.fileName, kmFileManager.fileExtension from KMFileManager kmFileManager " + "where kmFileManager.fileUID = :fileUID") List getFileNameByUID(@Param("fileUID") String fileUID); + + //newChange + @Query("SELECT km FROM KMFileManager km WHERE km.subCategoryID = :subCategoryID AND km.deleted = false") + List getFilesBySubCategoryID(@Param("subCategoryID") Integer subCategoryID); } 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 1a86fad0..df34dd5b 100644 --- a/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java +++ b/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java @@ -125,6 +125,78 @@ 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() + "/"; +// +// documentPath += version + "/"; +// documentPath += kmFileManager.getFileName(); +// kmFileManager.setKmUploadStatus(KM_UPLOADSTATUS_STARTED); +// String uuid = kmService.createDocument(documentPath, tempFilePath + "/" + kmFileManager.getFileName()); +// if (uuid != null) { +// kmFileManager.setKmUploadStatus(KM_UPLOADSTATUS_COMPLETED); +// kmFileManager.setFileUID(uuid); +// savedFileManagers.add(kmFileManagerRepository.save(kmFileManager)); +// if (kmFileManager.getSubCategoryID() != null) { +// updateSubcategoryFilePath(kmFileManager); +// } +// } +// } +// } +// } +// catch(Exception e) +// { +// logger.error("error " + e.getMessage()); +// } +// finally +// { +// if(newFile !=null) +// newFile.close(); +// if(fis !=null) +// fis.close(); +// } +// return savedFileManagers; +// } + private ArrayList addKMFile(Iterable kmFileManagers) throws IOException, NoSuchAlgorithmException { ArrayList savedFileManagers = new ArrayList(); @@ -175,6 +247,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); @@ -197,6 +272,7 @@ private ArrayList addKMFile(Iterable kmFileManager return savedFileManagers; } + private void updateSubcategoryFilePath(KMFileManager kmFileManager) { subCategoryRepository.updateFilePath(kmFileManager.getSubCategoryID(), kmFileManager.getFileUID()); } diff --git a/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java b/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java index fe081acb..e1010cf6 100644 --- a/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java +++ b/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java @@ -57,6 +57,7 @@ import com.iemr.common.utils.exception.IEMRException; import com.iemr.common.utils.mapper.InputMapper; import com.iemr.common.data.common.DocFileManager; +import com.iemr.common.data.kmfilemanager.KMFileManager; @Service @PropertySource("classpath:/application.properties") @@ -133,29 +134,67 @@ public Iterable getCategories() { return categoriesList; } +// @Override +// public Iterable getSubCategories(String request) throws IEMRException, JsonMappingException, JsonProcessingException { +// ObjectMapper objectMapper = new ObjectMapper(); +// SubCategoryDetails subCategoryDetails = objectMapper.readValue(request, SubCategoryDetails.class); +// List subCategoriesList = new ArrayList(); +// ArrayList lists = subCategoryRepository.findByCategoryID(subCategoryDetails.getCategoryID()); +// for (Object[] objects : lists) { +// if (objects != null && objects.length > 1) { +// String SubCatFilePath = (String) objects[2]; +// String fileUIDAsURI = null; +// String fileNameWithExtension = null; +// if(SubCatFilePath!=null) { +// fileUIDAsURI=getFilePath(SubCatFilePath); +// List fileNameList = kmFileManagerRepository.getFileNameByUID(SubCatFilePath); +// Object[] fileobjects = fileNameList.get(0); +// fileNameWithExtension= (String)fileobjects[0]+ (String) fileobjects[1]; +// } +// subCategoriesList.add(new SubCategoryDetails((Integer) objects[0], (String) objects[1], SubCatFilePath, fileUIDAsURI, fileNameWithExtension)); +// } +// } +// return subCategoriesList; +// } + + //newChange @Override public Iterable getSubCategories(String request) throws IEMRException, JsonMappingException, JsonProcessingException { - ObjectMapper objectMapper = new ObjectMapper(); - SubCategoryDetails subCategoryDetails = objectMapper.readValue(request, SubCategoryDetails.class); - List subCategoriesList = new ArrayList(); - ArrayList lists = subCategoryRepository.findByCategoryID(subCategoryDetails.getCategoryID()); - for (Object[] objects : lists) { - if (objects != null && objects.length > 1) { - String SubCatFilePath = (String) objects[2]; - String fileUIDAsURI = null; - String fileNameWithExtension = null; - if(SubCatFilePath!=null) { - fileUIDAsURI=getFilePath(SubCatFilePath); - List fileNameList = kmFileManagerRepository.getFileNameByUID(SubCatFilePath); - Object[] fileobjects = fileNameList.get(0); - fileNameWithExtension= (String)fileobjects[0]+ (String) fileobjects[1]; - } - subCategoriesList.add(new SubCategoryDetails((Integer) objects[0], (String) objects[1], SubCatFilePath, fileUIDAsURI, fileNameWithExtension)); - } - } - return subCategoriesList; + ObjectMapper objectMapper = new ObjectMapper(); + SubCategoryDetails subCategoryDetails = objectMapper.readValue(request, SubCategoryDetails.class); + List subCategoriesList = new ArrayList<>(); + ArrayList lists = subCategoryRepository.findByCategoryID(subCategoryDetails.getCategoryID()); + + for (Object[] objects : lists) { + if (objects != null && objects.length > 1) { + Integer subCatId = (Integer) objects[0]; + String subCatName = (String) objects[1]; + + // Fetch all files under this subcategory from KMFileManager + List files = kmFileManagerRepository.getFilesBySubCategoryID(subCatId); + ArrayList fileList = new ArrayList<>(files); + + String fileURL = null; + String fileNameWithExtension = null; + + if (!fileList.isEmpty()) { + KMFileManager firstFile = fileList.get(0); // Just for representative file URL and name + fileURL = getFilePath(firstFile.getFileUID()); + fileNameWithExtension = firstFile.getFileName() + firstFile.getFileExtension(); + } + + SubCategoryDetails subCategory = new SubCategoryDetails(subCatId, subCatName); + subCategory.setFileManger(fileList); // Attach all files here + subCategory.setFileURL(fileURL); // Representative file URL + subCategory.setFileNameWithExtension(fileNameWithExtension); // Representative file name+ext + + subCategoriesList.add(subCategory); + } + } + return subCategoriesList; } + private String getFilePath(String fileUID) { String fileUIDAsURI = null; From eef6bb37ce77cf0cab714c38eec9a465501fd823 Mon Sep 17 00:00:00 2001 From: SR20290919 Date: Fri, 27 Jun 2025 16:57:50 +0530 Subject: [PATCH 06/16] removed commented code --- .../KMFileManagerServiceImpl.java | 71 ------------------- .../service/services/CommonServiceImpl.java | 22 ------ 2 files changed, 93 deletions(-) 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 df34dd5b..7a24c6da 100644 --- a/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java +++ b/src/main/java/com/iemr/common/service/kmfilemanager/KMFileManagerServiceImpl.java @@ -125,77 +125,6 @@ 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() + "/"; -// -// documentPath += version + "/"; -// documentPath += kmFileManager.getFileName(); -// kmFileManager.setKmUploadStatus(KM_UPLOADSTATUS_STARTED); -// String uuid = kmService.createDocument(documentPath, tempFilePath + "/" + kmFileManager.getFileName()); -// if (uuid != null) { -// kmFileManager.setKmUploadStatus(KM_UPLOADSTATUS_COMPLETED); -// kmFileManager.setFileUID(uuid); -// savedFileManagers.add(kmFileManagerRepository.save(kmFileManager)); -// if (kmFileManager.getSubCategoryID() != null) { -// updateSubcategoryFilePath(kmFileManager); -// } -// } -// } -// } -// } -// catch(Exception e) -// { -// logger.error("error " + e.getMessage()); -// } -// finally -// { -// if(newFile !=null) -// newFile.close(); -// if(fis !=null) -// fis.close(); -// } -// return savedFileManagers; -// } private ArrayList addKMFile(Iterable kmFileManagers) throws IOException, NoSuchAlgorithmException { diff --git a/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java b/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java index e1010cf6..ff6f83e9 100644 --- a/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java +++ b/src/main/java/com/iemr/common/service/services/CommonServiceImpl.java @@ -134,28 +134,6 @@ public Iterable getCategories() { return categoriesList; } -// @Override -// public Iterable getSubCategories(String request) throws IEMRException, JsonMappingException, JsonProcessingException { -// ObjectMapper objectMapper = new ObjectMapper(); -// SubCategoryDetails subCategoryDetails = objectMapper.readValue(request, SubCategoryDetails.class); -// List subCategoriesList = new ArrayList(); -// ArrayList lists = subCategoryRepository.findByCategoryID(subCategoryDetails.getCategoryID()); -// for (Object[] objects : lists) { -// if (objects != null && objects.length > 1) { -// String SubCatFilePath = (String) objects[2]; -// String fileUIDAsURI = null; -// String fileNameWithExtension = null; -// if(SubCatFilePath!=null) { -// fileUIDAsURI=getFilePath(SubCatFilePath); -// List fileNameList = kmFileManagerRepository.getFileNameByUID(SubCatFilePath); -// Object[] fileobjects = fileNameList.get(0); -// fileNameWithExtension= (String)fileobjects[0]+ (String) fileobjects[1]; -// } -// subCategoriesList.add(new SubCategoryDetails((Integer) objects[0], (String) objects[1], SubCatFilePath, fileUIDAsURI, fileNameWithExtension)); -// } -// } -// return subCategoriesList; -// } //newChange @Override From 9a7c74156e21ba2ba6c20f226245f3c216a03a58 Mon Sep 17 00:00:00 2001 From: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Date: Mon, 30 Jun 2025 10:28:24 +0530 Subject: [PATCH 07/16] Add Security Check to Prevent User Enumeration (#240) * fix: user enmeration fix for login and forgot password * fix: user enmeration fix for login and forgot password * fix: user enmeration fix for login and forgot password --- .../controller/users/IEMRAdminController.java | 92 ++++++++++++------- .../users/IEMRAdminUserServiceImpl.java | 76 ++++++++------- 2 files changed, 103 insertions(+), 65 deletions(-) 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 81acd8ca..d8a43b35 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -156,7 +156,7 @@ public String userAuthenticate( logger.info("CAPTCHA validated successfully for user: {}", m_User.getUserName()); } else { logger.warn("CAPTCHA token missing for user: {}", m_User.getUserName()); - response.setError(new IEMRException("CAPTCHA token is required")); + response.setError(new IEMRException("CAPTCHA validation failed. Please try again.")); return response.toString(); } } else { @@ -254,20 +254,24 @@ public ResponseEntity refreshToken(@RequestBody Map request) try { if (jwtUtil.validateToken(refreshToken) == null) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid token"); + logger.warn("Token validation failed: invalid token provided."); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized."); } Claims claims = jwtUtil.getAllClaimsFromToken(refreshToken); // Verify token type if (!"refresh".equals(claims.get("token_type", String.class))) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid token type"); + logger.warn("Token validation failed: incorrect token type in refresh request."); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized."); + } // Check revocation using JTI String jti = claims.getId(); if (!redisTemplate.hasKey("refresh:" + jti)) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Token revoked"); + logger.warn("Token validation failed: refresh token is revoked or not found in store."); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized."); } // Get user details @@ -277,11 +281,13 @@ public ResponseEntity refreshToken(@RequestBody Map request) // Validate that the user still exists and is active if (user == null) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("User not found"); + 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())) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("User account is inactive"); + logger.warn("Token validation failed: user account is inactive or not in 'Active' status."); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized."); } // Generate new tokens String newJwt = jwtUtil.generateToken(user.getUserName(), userId); @@ -302,10 +308,14 @@ public ResponseEntity refreshToken(@RequestBody Map request) return ResponseEntity.ok(tokens); } catch (ExpiredJwtException ex) { - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Token expired"); + logger.warn("Token validation failed: token has expired."); + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("Authentication failed. Please log in again."); } catch (Exception e) { logger.error("Refresh failed: ", e); - return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Token refresh failed"); + logger.error("Token refresh failed due to unexpected server error."); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("An unexpected error occurred. Please try again later."); } } @@ -321,10 +331,12 @@ public String logOutUserFromConcurrentSession( List mUsers = iemrAdminUserServiceImpl.userExitsCheck(m_User.getUserName()); if (mUsers == null || mUsers.size() <= 0) { - throw new IEMRException("User not found, please contact administrator"); - } else if (mUsers.size() > 1) - throw new IEMRException("More than 1 user found, please contact administrator"); - else if (mUsers.size() == 1) { + logger.error("User not found"); + throw new IEMRException("Logout request failed, please try again later"); + } else if (mUsers.size() > 1) { + logger.error("More than 1 user found"); + throw new IEMRException("Logout failed. Please retry or contact administrator"); + } else if (mUsers.size() == 1) { String previousTokenFromRedis = sessionObject .getSessionObject((mUsers.get(0).getUserName().toString().trim().toLowerCase())); if (previousTokenFromRedis != null) { @@ -332,7 +344,8 @@ else if (mUsers.size() == 1) { sessionObject.deleteSessionObject(previousTokenFromRedis); response.setResponse("User successfully logged out"); } else - throw new IEMRException("Unable to fetch session from redis"); + logger.error("Unable to fetch session from redis"); + throw new IEMRException("Session error. Please try again later"); } } else { throw new IEMRException("Invalid request object"); @@ -404,7 +417,7 @@ private void createUserMapping(User mUser, JSONObject resMap, JSONObject service previlegeObj.getJSONObject(serv).put("agentPassword", m_UserServiceRoleMapping.getAgentPassword()); } JSONArray roles = previlegeObj.getJSONObject(serv).getJSONArray("roles"); -// roles.put(new JSONObject(m_UserServiceRoleMapping.getM_Role().toString())); + // roles.put(new JSONObject(m_UserServiceRoleMapping.getM_Role().toString())); JSONObject roleObject = new JSONObject(m_UserServiceRoleMapping.getM_Role().toString()); roleObject.put("teleConsultation", m_UserServiceRoleMapping.getTeleConsultation()); roles.put(roleObject); @@ -506,7 +519,7 @@ public String superUserAuthenticate( response.setResponse(responseObj.toString()); } catch (Exception e) { logger.error("userAuthenticate failed with error " + e.getMessage(), e); - response.setError(e); + response.setError(5000, "Authentication failed. Please try again later."); // Generic fallback } logger.info("userAuthenticate response " + response.toString()); return response.toString(); @@ -563,7 +576,8 @@ public String getLoginResponse(HttpServletRequest request) { } if (jwtToken == null) { - throw new IEMRException("No authentication token found in header or cookie"); + 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 @@ -572,7 +586,9 @@ public String getLoginResponse(HttpServletRequest request) { // Get user details and prepare response User user = iemrAdminUserServiceImpl.getUserById(Long.parseLong(userId)); if (user == null) { - throw new IEMRException("User not found"); + logger.warn("User lookup failed for provided userId."); + throw new IEMRException("Authentication failed. Please try again."); + } String remoteAddress = request.getHeader("X-FORWARDED-FOR"); @@ -603,10 +619,13 @@ public String forgetPassword( List mUsers = iemrAdminUserServiceImpl.userExitsCheck(m_User.getUserName()); if (mUsers == null || mUsers.size() <= 0) { - throw new IEMRException("user not found, please contact administrator"); - } else if (mUsers.size() > 1) - throw new IEMRException("more than 1 user found, please contact administrator"); - else if (mUsers.size() == 1) { + logger.error("User not found"); + throw new IEMRException("Request failed, please try again later"); + } else if (mUsers.size() > 1) { + logger.error("More than 1 user found"); + throw new IEMRException("Request failed. Please retry again"); + + } else if (mUsers.size() == 1) { List> quesAnsList = new ArrayList<>(); Map quesAnsMap; Map resMap = new HashMap<>(); @@ -626,7 +645,7 @@ else if (mUsers.size() == 1) { } } catch (Exception e) { logger.error("forgetPassword failed with error " + e.getMessage(), e); - response.setError(e); + response.setError(5000, "ForgetPassword failed."); } logger.info("forgetPassword response " + response.toString()); return response.toString(); @@ -642,8 +661,11 @@ public String setPassword( int noOfRowModified = 0; List mUsers = iemrAdminUserServiceImpl.userExitsCheck(m_user.getUserName()); if (mUsers.size() != 1) { - throw new IEMRException( - "Set forgot password failed as the user does not exist or is not active or multiple user found.Please contact with administrator"); + logger.warn( + "Password reset failed for username '{}'. Reason: user not found, inactive, or multiple matches.", + m_user.getUserName()); + + throw new IEMRException("Unable to process your request. Please try again or contact support."); } User mUser = mUsers.get(0); String setStatus; @@ -660,7 +682,7 @@ public String setPassword( } catch (Exception e) { logger.error("setForgetPassword failed with error " + e.getMessage(), e); if (e.getMessage().equals( - "Set forgot password failed as the user does not exist or is not active or multiple user found.Please contact with administrator")) + "Unable to process your request. Please try again or contact support.")) response.setError(e); else response.setError(5000, e.getMessage()); @@ -681,7 +703,9 @@ public String changePassword( List mUsers = iemrAdminUserServiceImpl.userExitsCheck(changePassword.getUserName()); String changeReqResult; if (mUsers.size() != 1) { - throw new IEMRException("Change password failed with error as user is not available"); + logger.warn("Change password attempt failed. User not found or not available."); + + throw new IEMRException("Unable to change password. Please try again later"); } try { int validatePassword; @@ -710,7 +734,7 @@ public String changePassword( response.setResponse(changeReqResult); } catch (Exception e) { logger.error("changePassword failed with error " + e.getMessage(), e); - response.setError(e); + response.setError(5000, "Password change failed. Please try again later."); } logger.info("changePassword response " + response.toString()); return response.toString(); @@ -728,7 +752,7 @@ public String saveUserSecurityQuesAns( response.setResponse(responseData); } catch (Exception e) { logger.error("saveUserSecurityQuesAns failed with error " + e.getMessage(), e); - response.setError(e); + response.setError(5000, "Failed to save security questions. Please try again later."); } logger.info("saveUserSecurityQuesAns response " + response.toString()); return response.toString(); @@ -748,7 +772,7 @@ public String getSecurityts() { response.setResponse(test.toString()); } catch (Exception e) { logger.error("getsecurityquetions failed with error " + e.getMessage(), e); - response.setError(e); + response.setError(5000, "Unable to fetch security questions"); } logger.info("getsecurityquetions response " + response.toString()); return response.toString(); @@ -1034,7 +1058,7 @@ public String userAuthenticateByEncryption( response.setResponse(responseObj.toString()); } catch (Exception e) { logger.error("userAuthenticateByEncryption failed with error " + e.getMessage(), e); - response.setError(e); + response.setError(5000, "Request failed. Please try again."); } logger.info("userAuthenticateByEncryption response " + response.toString()); return response.toString(); @@ -1052,7 +1076,7 @@ public String getrolewrapuptime(@PathVariable("roleID") Integer roleID) { } response.setResponse(test.toString()); } catch (Exception e) { - response.setError(e); + response.setError(5000, "Request failed. Please try again."); } return response.toString(); } @@ -1079,8 +1103,8 @@ public String validateSecurityQuestionAndAnswer( } else throw new IEMRException("Invalid Request"); } catch (Exception e) { - response.setError(5000, e.getMessage()); - logger.error(e.toString()); + logger.error("validateSecurityQuestionAndAnswer failed: {}", e.toString()); + response.setError(5000, "Request failed. Please try again."); } logger.info("validateSecurityQuestionAndAnswer API response" + response.toString()); return response.toString(); @@ -1136,7 +1160,7 @@ public String userAuthenticateBhavya( response.setResponse(responseObj.toString()); } catch (Exception e) { logger.error("userAuthenticate failed with error " + e.getMessage(), e); - response.setError(e); + response.setError(5000, "Authentication failed. Please try again."); } logger.info("userAuthenticate response " + response.toString()); return response.toString(); 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 a0efd373..591180bd 100644 --- a/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java +++ b/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java @@ -224,7 +224,7 @@ public void setValidator(Validator validator) { public List userAuthenticate(String userName, String password) throws Exception { List users = iEMRUserRepositoryCustom.findByUserNameNew(userName); if (users.size() != 1) { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } else { if (users.get(0).getDeleted()) throw new IEMRException("Your account is locked or de-activated. Please contact administrator"); @@ -263,16 +263,18 @@ else if (users.get(0).getStatusID() > 2) user.setFailedAttempt(user.getFailedAttempt() + 1); user.setDeleted(true); user = iEMRUserRepositoryCustom.save(user); + logger.warn("User Account has been locked after reaching the limit of {} failed login attempts.", + ConfigProperties.getInteger("failedLoginAttempt")); + throw new IEMRException( - "User login failed due to incorrect username/password. Your account is locked due to " - + ConfigProperties.getInteger("failedLoginAttempt") - + " failed attempts. Please contact administrator."); + "Your account has been locked due to multiple failed login attempts. Please contact administrator."); } else { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); - throw new IEMRException("User login failed due to incorrect username/password. " - + (ConfigProperties.getInteger("failedLoginAttempt") - user.getFailedAttempt()) - + " more attempt left."); + logger.warn("Failed login attempt {} of {} for a user account.", + user.getFailedAttempt(), ConfigProperties.getInteger("failedLoginAttempt")); + throw new IEMRException( + "Your account has been locked due to multiple failed login attempts. Please contact administrator."); } } else { if (user.getFailedAttempt() != 0) { @@ -307,7 +309,7 @@ public User superUserAuthenticate(String userName, String password) throws Excep List users = iEMRUserRepositoryCustom.findByUserName(userName); if (users.size() != 1) { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } else { if (users.get(0).getDeleted()) throw new IEMRException("Your account is locked or de-activated. Please contact administrator"); @@ -344,16 +346,18 @@ else if (users.get(0).getStatusID() > 2) user.setFailedAttempt(user.getFailedAttempt() + 1); user.setDeleted(true); user = iEMRUserRepositoryCustom.save(user); + logger.warn("User Account has been locked after reaching the limit of {} failed login attempts.", + ConfigProperties.getInteger("failedLoginAttempt")); + throw new IEMRException( - "User login failed due to incorrect username/password. Your account is locked due to " - + ConfigProperties.getInteger("failedLoginAttempt") - + " failed attempts. Please contact administrator."); + "Your account has been locked due to multiple failed login attempts. Please contact administrator."); } else { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); - throw new IEMRException("User login failed due to incorrect username/password. " - + (ConfigProperties.getInteger("failedLoginAttempt") - user.getFailedAttempt()) - + " more attempt left."); + logger.warn("Failed login attempt {} of {} for a user account.", + user.getFailedAttempt(), ConfigProperties.getInteger("failedLoginAttempt")); + throw new IEMRException( + "Your account has been locked due to multiple failed login attempts. Please contact administrator."); } } else { if (user.getFailedAttempt() != 0) { @@ -376,10 +380,10 @@ public LoginResponseModel userAuthenticateV1(LoginRequestModel loginRequest, Str User user = users.get(0); try { if (!securePassword.validatePasswordExisting(loginRequest.getPassword(), user.getPassword())) { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } } catch (Exception e) { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } loginResponseModel = userMapper.userDataToLoginResponse(user); logger.info("Login response is " + loginResponseModel.toString()); @@ -391,7 +395,7 @@ public LoginResponseModel userAuthenticateV1(LoginRequestModel loginRequest, Str // loginResponseModel.setHostName(hostName); // loginResponseModel.setIpAddress(ipAddress); } else { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } return loginResponseModel; @@ -614,7 +618,8 @@ public String saveUserSecurityQuesAns(Iterable m_UserSecur User users = iEMRUserRepositoryCustom .findUserByUserID(m_UserSecurityQMapping.iterator().next().getUserID()); if (users == null) { - throw new IEMRException("User does not exist or is not active"); + logger.warn("User validation failed: user not found for provided ID."); + throw new IEMRException("Invalid user. Please contact administrator."); } Iterable obj = iEMRUserSecurityQuesAnsRepository.saveAll(m_UserSecurityQMapping); @@ -627,7 +632,9 @@ public String saveUserSecurityQuesAns(Iterable m_UserSecur sessionObject.deleteSessionObject((users.getUserID().toString() + users.getUserName())); return generateTransactionIdForPasswordChange(users); } else { - throw new IEMRException("Failed to save security question and answers, Please try again"); + logger.error( + "Failed to save user security questions. Repository save operation returned empty result."); + throw new IEMRException("Unable to complete the operation. Please try again later."); } } else throw new IEMRException("Invalid user, please contact administrator"); @@ -867,9 +874,9 @@ public JSONObject generateKeyAndValidateIP(JSONObject responseObj, String ipAddr throws JSONException, NoSuchAlgorithmException, IEMRException { String key = generateKey(responseObj); // commented the below code to restrict IP address and hostname to be sent on UI -// responseObj.put("loginIPAddress", ipAddress); -// responseObj.put("ipAddress", ipAddress); -// responseObj.put("hostName", hostName); + // responseObj.put("loginIPAddress", ipAddress); + // responseObj.put("ipAddress", ipAddress); + // responseObj.put("hostName", hostName); responseObj = validator.updateCacheObj(responseObj, key, ""); setConcurrentCheckSessionObject(responseObj, key); return responseObj; @@ -958,10 +965,10 @@ public void userForceLogout(ForceLogoutRequestModel request) throws Exception { } try { if (!securePassword.validatePasswordExisting(request.getPassword(), users.get(0).getPassword())) { - throw new Exception("Force logout failed due to incorrect password"); + throw new Exception("Force logout failed"); } } catch (Exception e) { - throw new Exception("Force logout failed due to incorrect password"); + throw new Exception("Force logout failed"); } userForceLogout(request, users.get(0)); } @@ -1049,15 +1056,15 @@ public List userAuthenticateByEncryption(String req) throws Exception { LoginRequestModel m_user = InputMapper.gson().fromJson(jsonreq, LoginRequestModel.class); List users = iEMRUserRepositoryCustom.findByUserName(m_user.getUserName()); if (users.size() != 1) { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } User user = users.get(0); try { if (!securePassword.validatePasswordExisting(m_user.getPassword(), user.getPassword())) { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } } catch (Exception e) { - throw new IEMRException("User login failed due to incorrect username/password"); + throw new IEMRException("Invalid username or password"); } user.setM_UserServiceRoleMapping(getUserServiceRoleMapping(user.getUserID())); return users; @@ -1105,7 +1112,10 @@ public String validateQuestionAndAnswersForPasswordChange(JsonObject request) th if (request.has("userName") && request.get("userName") != null) { List users = iEMRUserRepositoryCustom.findByUserName(request.get("userName").getAsString()); if (users.size() != 1) { - throw new IEMRException("User does not exist or is not active or more than 1 user found"); + logger.warn("User validation failed: not found or duplicate entries for username '{}'", + request.get("userName").getAsString()); + throw new IEMRException("Unable to validate credentials. Please contact administrator."); + } User user = users.get(0); sessionObject.deleteSessionObject((user.getUserID().toString() + user.getUserName())); @@ -1118,8 +1128,12 @@ public String validateQuestionAndAnswersForPasswordChange(JsonObject request) th user.getUserID(), securityAnswers.getQuestionId(), securityAnswers.getAnswer()); if (userSecurityQuestionAnswers == null - || userSecurityQuestionAnswers.getUserSecurityQAID() == null) - throw new IEMRException("Security answers does not match"); + || userSecurityQuestionAnswers.getUserSecurityQAID() == null) { + logger.warn("Security answer mismatch for userId={}, questionId={}", + user.getUserID(), securityAnswers.getQuestionId()); + throw new IEMRException( + "We couldn't verify your answers. Please try again"); + } pointer++; } @@ -1132,7 +1146,7 @@ public String validateQuestionAndAnswersForPasswordChange(JsonObject request) th throw new IEMRException("Invalid questions, validation failed, please contact administrator"); } else - throw new IEMRException("Invalid/NULL user name"); + throw new IEMRException("Invalid request. Please try again."); } catch (Exception e) { logger.error(e.getMessage(), e); throw new IEMRException(e.getMessage()); From 7be379683cd0967203ec22c1a2b27e4b5a39c132 Mon Sep 17 00:00:00 2001 From: SR20290919 Date: Mon, 30 Jun 2025 12:14:36 +0530 Subject: [PATCH 08/16] removed commented code --- .../com/iemr/common/data/kmfilemanager/KMFileManager.java | 5 +---- .../repository/kmfilemanager/KMFileManagerRepository.java | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java b/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java index 6409837f..ed7f0b84 100644 --- a/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java +++ b/src/main/java/com/iemr/common/data/kmfilemanager/KMFileManager.java @@ -110,11 +110,8 @@ public class KMFileManager { @Transient @Expose private Integer categoryID; -// @Transient -// @Expose -// private Integer subCategoryID; - @Column(name = "SubCategoryID") // 🔴 DB-mapped field to associate files with a subcategory + @Column(name = "SubCategoryID") @Expose private Integer subCategoryID; @Transient diff --git a/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java b/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java index 615c841b..f1e8187d 100644 --- a/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java +++ b/src/main/java/com/iemr/common/repository/kmfilemanager/KMFileManagerRepository.java @@ -75,7 +75,7 @@ ArrayList getKMFileLists(@Param("providerServiceMapID") Integer p + "where kmFileManager.fileUID = :fileUID") List getFileNameByUID(@Param("fileUID") String fileUID); - //newChange + @Query("SELECT km FROM KMFileManager km WHERE km.subCategoryID = :subCategoryID AND km.deleted = false") List getFilesBySubCategoryID(@Param("subCategoryID") Integer subCategoryID); From a0a362ff4ceaa6dec232d921126fa3cbeb79637e Mon Sep 17 00:00:00 2001 From: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Date: Tue, 1 Jul 2025 12:37:34 +0530 Subject: [PATCH 09/16] fix:user enumeration (#242) --- .../controller/users/IEMRAdminController.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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 d8a43b35..48d10fb3 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -519,7 +519,7 @@ public String superUserAuthenticate( response.setResponse(responseObj.toString()); } catch (Exception e) { logger.error("userAuthenticate failed with error " + e.getMessage(), e); - response.setError(5000, "Authentication failed. Please try again later."); // Generic fallback + response.setError(e); } logger.info("userAuthenticate response " + response.toString()); return response.toString(); @@ -620,10 +620,10 @@ public String forgetPassword( if (mUsers == null || mUsers.size() <= 0) { logger.error("User not found"); - throw new IEMRException("Request failed, please try again later"); + throw new IEMRException("If the username is valid, you will be asked a security question"); } else if (mUsers.size() > 1) { logger.error("More than 1 user found"); - throw new IEMRException("Request failed. Please retry again"); + throw new IEMRException("If the username is valid, you will be asked a security question"); } else if (mUsers.size() == 1) { List> quesAnsList = new ArrayList<>(); @@ -645,7 +645,7 @@ public String forgetPassword( } } catch (Exception e) { logger.error("forgetPassword failed with error " + e.getMessage(), e); - response.setError(5000, "ForgetPassword failed."); + response.setError(e); } logger.info("forgetPassword response " + response.toString()); return response.toString(); @@ -734,7 +734,7 @@ public String changePassword( response.setResponse(changeReqResult); } catch (Exception e) { logger.error("changePassword failed with error " + e.getMessage(), e); - response.setError(5000, "Password change failed. Please try again later."); + response.setError(e); } logger.info("changePassword response " + response.toString()); return response.toString(); @@ -752,7 +752,7 @@ public String saveUserSecurityQuesAns( response.setResponse(responseData); } catch (Exception e) { logger.error("saveUserSecurityQuesAns failed with error " + e.getMessage(), e); - response.setError(5000, "Failed to save security questions. Please try again later."); + response.setError(e); } logger.info("saveUserSecurityQuesAns response " + response.toString()); return response.toString(); @@ -1058,7 +1058,7 @@ public String userAuthenticateByEncryption( response.setResponse(responseObj.toString()); } catch (Exception e) { logger.error("userAuthenticateByEncryption failed with error " + e.getMessage(), e); - response.setError(5000, "Request failed. Please try again."); + response.setError(e); } logger.info("userAuthenticateByEncryption response " + response.toString()); return response.toString(); @@ -1076,7 +1076,7 @@ public String getrolewrapuptime(@PathVariable("roleID") Integer roleID) { } response.setResponse(test.toString()); } catch (Exception e) { - response.setError(5000, "Request failed. Please try again."); + response.setError(e); } return response.toString(); } @@ -1104,7 +1104,7 @@ public String validateSecurityQuestionAndAnswer( throw new IEMRException("Invalid Request"); } catch (Exception e) { logger.error("validateSecurityQuestionAndAnswer failed: {}", e.toString()); - response.setError(5000, "Request failed. Please try again."); + response.setError(5000, e.getMessage()); } logger.info("validateSecurityQuestionAndAnswer API response" + response.toString()); return response.toString(); @@ -1160,7 +1160,7 @@ public String userAuthenticateBhavya( response.setResponse(responseObj.toString()); } catch (Exception e) { logger.error("userAuthenticate failed with error " + e.getMessage(), e); - response.setError(5000, "Authentication failed. Please try again."); + response.setError(e); } logger.info("userAuthenticate response " + response.toString()); return response.toString(); From 2f902f816e5b7c0f4227ca4ee106773c254a2551 Mon Sep 17 00:00:00 2001 From: Amoghavarsh <93114621+5Amogh@users.noreply.github.com> Date: Wed, 2 Jul 2025 11:01:57 +0530 Subject: [PATCH 10/16] fix: AMM-1677 - rendering only grievances who have consent (#244) --- .../com/iemr/common/dto/grivance/GrievanceWorklistDTO.java | 6 ++++-- .../service/grievance/GrievanceHandlingServiceImpl.java | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/iemr/common/dto/grivance/GrievanceWorklistDTO.java b/src/main/java/com/iemr/common/dto/grivance/GrievanceWorklistDTO.java index b8184162..6364b7f6 100644 --- a/src/main/java/com/iemr/common/dto/grivance/GrievanceWorklistDTO.java +++ b/src/main/java/com/iemr/common/dto/grivance/GrievanceWorklistDTO.java @@ -39,13 +39,14 @@ public class GrievanceWorklistDTO implements Serializable { private String age; private Boolean retryNeeded; private Integer callCounter; - private Timestamp lastCall; + private Timestamp lastCall; + private Boolean beneficiaryConsent; public GrievanceWorklistDTO(String complaintID,Long grievanceId, String subjectOfComplaint, String complaint, Long beneficiaryRegID, Integer providerServiceMapID,String primaryNumber,String severety,String state, Integer userId, Boolean deleted, String createdBy, Timestamp createdDate, Timestamp lastModDate, Boolean isCompleted,String firstName, String lastName, String gender, String district, Long beneficiaryID, String age, - Boolean retryNeeded, Integer callCounter, Timestamp lastCall) { + Boolean retryNeeded, Integer callCounter, Timestamp lastCall, Boolean beneficiaryConsent) { super(); this.complaintID = complaintID; this.grievanceId = grievanceId; @@ -71,6 +72,7 @@ public GrievanceWorklistDTO(String complaintID,Long grievanceId, String subjectO this.retryNeeded = retryNeeded; this.callCounter = callCounter; this.lastCall = lastCall; + this.beneficiaryConsent = beneficiaryConsent; } diff --git a/src/main/java/com/iemr/common/service/grievance/GrievanceHandlingServiceImpl.java b/src/main/java/com/iemr/common/service/grievance/GrievanceHandlingServiceImpl.java index 68e8e76e..ed643417 100644 --- a/src/main/java/com/iemr/common/service/grievance/GrievanceHandlingServiceImpl.java +++ b/src/main/java/com/iemr/common/service/grievance/GrievanceHandlingServiceImpl.java @@ -296,7 +296,7 @@ public List getFormattedGrievanceData(String request) thro // Loop through the worklist data and format the response for (Object[] row : worklistData) { - if (row == null || row.length < 22) + if (row == null || row.length < 24) { logger.warn("invalid row data received"); continue; @@ -334,7 +334,8 @@ public List getFormattedGrievanceData(String request) thro ageFormatted, (Boolean) row[21], // retryNeeded (Integer) row[22], // callCounter - (Timestamp) row[13] //lastCall + (Timestamp) row[13], // lastCall + (Boolean) row[23] //beneficiaryConsent ); From 46195c5de7d67c8777fd74fe9470ec9dab9f70f3 Mon Sep 17 00:00:00 2001 From: Amoghavarsh <93114621+5Amogh@users.noreply.github.com> Date: Fri, 4 Jul 2025 16:44:08 +0530 Subject: [PATCH 11/16] fix: AMM-1701 callcounter issue fix (#254) * fix: AMM-1677 - rendering only grievances who have consent * fix: AMM-1701 callcounter issue fix --- .../grievance/GrievanceDataSyncImpl.java | 59 +++++++++++-------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/iemr/common/service/grievance/GrievanceDataSyncImpl.java b/src/main/java/com/iemr/common/service/grievance/GrievanceDataSyncImpl.java index 5a05b94f..35c9b57b 100644 --- a/src/main/java/com/iemr/common/service/grievance/GrievanceDataSyncImpl.java +++ b/src/main/java/com/iemr/common/service/grievance/GrievanceDataSyncImpl.java @@ -579,41 +579,48 @@ public String completeGrievanceCall(String request) throws Exception { // Logic for reattempt based on call group type and call type boolean isRetryNeeded = grievanceCallStatus.getRetryNeeded(); - if ((null != grievanceCallStatus.getComplaintResolution() - && grievanceCallStatus.getComplaintResolution().equalsIgnoreCase("Resolved")) || (callGroupType.equalsIgnoreCase("Valid") && (callType.equalsIgnoreCase("Valid") || callType.equals("Test Call")))) { + boolean isResolved = grievanceCallStatus.getComplaintResolution() != null + && grievanceCallStatus.getComplaintResolution().equalsIgnoreCase("Resolved"); + boolean isValidGroup = callGroupType.equalsIgnoreCase("Valid") + && (callType.equalsIgnoreCase("Valid") || callType.equals("Test Call")); + boolean isInvalidGroup = callGroupType.equalsIgnoreCase("Invalid") + && (callType.equalsIgnoreCase("Wrong Number") || callType.equalsIgnoreCase("Invalid Call")); + + if (isResolved) { + // 1) Any resolved call → complete, no retry isRetryNeeded = false; updateCount = grievanceDataRepo.updateCompletedStatusInCall(true, false, complaintID, userID, beneficiaryRegID); - } - else if (callGroupType.equalsIgnoreCase("Invalid") && (callType.equalsIgnoreCase("Wrong Number") || callType.equalsIgnoreCase("Invalid Call"))) { + + } else if (isValidGroup) { + // 2) Valid but not resolved → leave open, retry allowed + isRetryNeeded = true; + updateCount = grievanceDataRepo.updateCompletedStatusInCall(false, true, complaintID, userID, beneficiaryRegID); + + } else if (isInvalidGroup) { + // 3) Invalid calls → complete, no retry isRetryNeeded = false; - updateCount = grievanceDataRepo.updateCompletedStatusInCall(true, isRetryNeeded, complaintID, userID, - beneficiaryRegID); - }else { + updateCount = grievanceDataRepo.updateCompletedStatusInCall(true, false, complaintID, userID, beneficiaryRegID); + + } else { + // 4) All other cases (e.g. unreachable) → leave open, retry allowed isRetryNeeded = true; - updateCount = grievanceDataRepo.updateCompletedStatusInCall(false, isRetryNeeded, complaintID, - userID, beneficiaryRegID); + updateCount = grievanceDataRepo.updateCompletedStatusInCall(false, true, complaintID, userID, beneficiaryRegID); } - // Check if max attempts (3) are reached + + //Call counter update if (isRetryNeeded && grievanceCallStatus.getCallCounter() < grievanceAllocationRetryConfiguration) { grievanceCallStatus.setCallCounter(grievanceCallStatus.getCallCounter() + 1); - updateCallCounter = grievanceDataRepo.updateCallCounter(grievanceCallStatus.getCallCounter(), - isRetryNeeded, grievanceCallRequest.getComplaintID(), - grievanceCallRequest.getBeneficiaryRegID(), - grievanceCallRequest.getUserID()); - if (updateCallCounter > 0) - response = "Successfully closing call"; - else { - response = "failure in closing call"; - } - } else if (grievanceCallStatus.getCallCounter() == grievanceAllocationRetryConfiguration) { - // Max attempts reached, no further reattempt + updateCallCounter = grievanceDataRepo.updateCallCounter( + grievanceCallStatus.getCallCounter(), true, complaintID, beneficiaryRegID, userID); + response = (updateCallCounter > 0) ? "Successfully closing call" : "failure in closing call"; + + } else if (grievanceCallStatus.getCallCounter() >= grievanceAllocationRetryConfiguration) { + // Max attempts reached → treated as “complete” isRetryNeeded = false; - // isCompleted = true; - updateCount = grievanceDataRepo.updateCompletedStatusInCall(isCompleted, isRetryNeeded, complaintID, - userID, beneficiaryRegID); - response = "max_attempts_reached"; // Indicate that max attempts are reached + updateCount = grievanceDataRepo.updateCompletedStatusInCall(true, false, complaintID, userID, beneficiaryRegID); + response = "max_attempts_reached"; - }else if(updateCount > 0) { + } else if (updateCount > 0) { response = "Successfully closing call"; } From c8db2251fc16f0cedefc0267c6805d2761bafb9a Mon Sep 17 00:00:00 2001 From: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:59:30 +0530 Subject: [PATCH 12/16] fix: username or password error mesage shown with failed attempt (#265) --- .../controller/users/IEMRAdminController.java | 4 +- .../users/IEMRAdminUserServiceImpl.java | 47 ++++++++++++------- 2 files changed, 33 insertions(+), 18 deletions(-) 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 48d10fb3..28c7e4b9 100644 --- a/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java +++ b/src/main/java/com/iemr/common/controller/users/IEMRAdminController.java @@ -620,10 +620,10 @@ public String forgetPassword( if (mUsers == null || mUsers.size() <= 0) { logger.error("User not found"); - throw new IEMRException("If the username is valid, you will be asked a security question"); + throw new IEMRException("If the username is registered, you will be asked a security question"); } else if (mUsers.size() > 1) { logger.error("More than 1 user found"); - throw new IEMRException("If the username is valid, you will be asked a security question"); + throw new IEMRException("If the username is registered, you will be asked a security question"); } else if (mUsers.size() == 1) { List> quesAnsList = new ArrayList<>(); 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 591180bd..05854843 100644 --- a/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java +++ b/src/main/java/com/iemr/common/service/users/IEMRAdminUserServiceImpl.java @@ -220,16 +220,19 @@ public void setValidator(Validator validator) { this.validator = validator; } + private void checkUserAccountStatus(User user) throws IEMRException { + if (user.getDeleted()) { + throw new IEMRException("Your account is locked or de-activated. Please contact administrator"); + } else if (user.getStatusID() > 2) { + throw new IEMRException("Your account is not active. Please contact administrator"); + } + } + @Override public List userAuthenticate(String userName, String password) throws Exception { List users = iEMRUserRepositoryCustom.findByUserNameNew(userName); if (users.size() != 1) { throw new IEMRException("Invalid username or password"); - } else { - if (users.get(0).getDeleted()) - throw new IEMRException("Your account is locked or de-activated. Please contact administrator"); - else if (users.get(0).getStatusID() > 2) - throw new IEMRException("Your account is not active. Please contact administrator"); } int failedAttempt = 0; if (failedLoginAttempt != null) @@ -241,6 +244,7 @@ else if (users.get(0).getStatusID() > 2) int validatePassword; validatePassword = securePassword.validatePassword(password, user.getPassword()); if (validatePassword == 1) { + checkUserAccountStatus(user); int iterations = 1001; char[] chars = password.toCharArray(); byte[] salt = getSalt(); @@ -254,12 +258,19 @@ else if (users.get(0).getStatusID() > 2) iEMRUserRepositoryCustom.save(user); } else if (validatePassword == 2) { + checkUserAccountStatus(user); iEMRUserRepositoryCustom.save(user); } else if (validatePassword == 3) { + checkUserAccountStatus(user); iEMRUserRepositoryCustom.save(user); } else if (validatePassword == 0) { - if (user.getFailedAttempt() + 1 >= failedAttempt) { + if (user.getFailedAttempt() + 1 < failedAttempt) { + user.setFailedAttempt(user.getFailedAttempt() + 1); + user = iEMRUserRepositoryCustom.save(user); + logger.warn("User Password Wrong"); + throw new IEMRException("Invalid username or password"); + } else if (user.getFailedAttempt() + 1 >= failedAttempt) { user.setFailedAttempt(user.getFailedAttempt() + 1); user.setDeleted(true); user = iEMRUserRepositoryCustom.save(user); @@ -267,16 +278,17 @@ else if (users.get(0).getStatusID() > 2) ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Your account has been locked due to multiple failed login attempts. Please contact administrator."); + "Invalid username or password. Please contact administrator."); } else { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); logger.warn("Failed login attempt {} of {} for a user account.", user.getFailedAttempt(), ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Your account has been locked due to multiple failed login attempts. Please contact administrator."); + "Invalid username or password. Please contact administrator."); } } else { + checkUserAccountStatus(user); if (user.getFailedAttempt() != 0) { user.setFailedAttempt(0); user = iEMRUserRepositoryCustom.save(user); @@ -310,11 +322,6 @@ public User superUserAuthenticate(String userName, String password) throws Excep if (users.size() != 1) { throw new IEMRException("Invalid username or password"); - } else { - if (users.get(0).getDeleted()) - throw new IEMRException("Your account is locked or de-activated. Please contact administrator"); - else if (users.get(0).getStatusID() > 2) - throw new IEMRException("Your account is not active. Please contact administrator"); } int failedAttempt = 0; if (failedLoginAttempt != null) @@ -326,6 +333,7 @@ else if (users.get(0).getStatusID() > 2) int validatePassword; validatePassword = securePassword.validatePassword(password, user.getPassword()); if (validatePassword == 1) { + checkUserAccountStatus(user); int iterations = 1001; char[] chars = password.toCharArray(); byte[] salt = getSalt(); @@ -339,10 +347,16 @@ else if (users.get(0).getStatusID() > 2) iEMRUserRepositoryCustom.save(user); } else if (validatePassword == 2) { + checkUserAccountStatus(user); iEMRUserRepositoryCustom.save(user); } else if (validatePassword == 0) { - if (user.getFailedAttempt() + 1 >= failedAttempt) { + if (user.getFailedAttempt() + 1 < failedAttempt) { + user.setFailedAttempt(user.getFailedAttempt() + 1); + user = iEMRUserRepositoryCustom.save(user); + logger.warn("User Password Wrong"); + throw new IEMRException("Invalid username or password"); + } else if (user.getFailedAttempt() + 1 >= failedAttempt) { user.setFailedAttempt(user.getFailedAttempt() + 1); user.setDeleted(true); user = iEMRUserRepositoryCustom.save(user); @@ -350,16 +364,17 @@ else if (users.get(0).getStatusID() > 2) ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Your account has been locked due to multiple failed login attempts. Please contact administrator."); + "Invalid username or password. Please contact administrator."); } else { user.setFailedAttempt(user.getFailedAttempt() + 1); user = iEMRUserRepositoryCustom.save(user); logger.warn("Failed login attempt {} of {} for a user account.", user.getFailedAttempt(), ConfigProperties.getInteger("failedLoginAttempt")); throw new IEMRException( - "Your account has been locked due to multiple failed login attempts. Please contact administrator."); + "Invalid username or password. Please contact administrator."); } } else { + checkUserAccountStatus(user); if (user.getFailedAttempt() != 0) { user.setFailedAttempt(0); user = iEMRUserRepositoryCustom.save(user); From ae0971459f0546e57768652fbfcf56c64c2b8994 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Jul 2025 10:06:29 +0530 Subject: [PATCH 13/16] dynamic from feature --- .../dynamicForm/DynamicFormController.java | 96 ++++++++-- .../data/dynamic_from/FormDefinition.java | 30 +++ .../common/data/dynamic_from/FormEntity.java | 27 --- .../common/data/dynamic_from/FormField.java | 59 ++++++ .../common/data/dynamic_from/FormModule.java | 23 +++ .../data/dynamic_from/ModuleEntity.java | 23 --- .../iemr/common/dto/dynamicForm/FieldDTO.java | 25 +++ .../dto/dynamicForm/FieldResponseDTO.java | 24 +++ .../iemr/common/dto/dynamicForm/FormDTO.java | 10 + .../common/dto/dynamicForm/FormFieldDTO.java | 23 --- .../dto/dynamicForm/FormResponseDTO.java | 13 ++ .../dto/dynamicForm/FormTypeEntityDTO.java | 18 -- .../dynamicForm/GroupedFieldResponseDTO.java | 11 ++ .../common/dto/dynamicForm/ModuleDTO.java | 8 + .../dto/dynamicForm/ModuleEntityDTO.java | 12 -- .../dynamic_form/FieldRepository.java | 12 ++ .../dynamic_form/FormRepository.java | 14 ++ .../dynamic_form/FormTypeRepository.java | 8 - .../dynamic_form/ModuleRepository.java | 4 +- .../dynamicForm/FormMasterService.java | 22 +++ .../dynamicForm/FormMasterServiceImpl.java | 177 ++++++++++++++++++ .../service/dynamicForm/FormTypeService.java | 35 ---- .../service/dynamicForm/ModuleService.java | 26 --- .../exception/GlobalExceptionHandler.java | 36 ++++ .../common/utils/response/ApiResponse.java | 31 +++ 25 files changed, 578 insertions(+), 189 deletions(-) create mode 100644 src/main/java/com/iemr/common/data/dynamic_from/FormDefinition.java delete mode 100644 src/main/java/com/iemr/common/data/dynamic_from/FormEntity.java create mode 100644 src/main/java/com/iemr/common/data/dynamic_from/FormField.java create mode 100644 src/main/java/com/iemr/common/data/dynamic_from/FormModule.java delete mode 100644 src/main/java/com/iemr/common/data/dynamic_from/ModuleEntity.java create mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/FieldDTO.java create mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/FieldResponseDTO.java create mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/FormDTO.java delete mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/FormFieldDTO.java create mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/FormResponseDTO.java delete mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/FormTypeEntityDTO.java create mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/GroupedFieldResponseDTO.java create mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/ModuleDTO.java delete mode 100644 src/main/java/com/iemr/common/dto/dynamicForm/ModuleEntityDTO.java create mode 100644 src/main/java/com/iemr/common/repository/dynamic_form/FieldRepository.java create mode 100644 src/main/java/com/iemr/common/repository/dynamic_form/FormRepository.java delete mode 100644 src/main/java/com/iemr/common/repository/dynamic_form/FormTypeRepository.java create mode 100644 src/main/java/com/iemr/common/service/dynamicForm/FormMasterService.java create mode 100644 src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java delete mode 100644 src/main/java/com/iemr/common/service/dynamicForm/FormTypeService.java delete mode 100644 src/main/java/com/iemr/common/service/dynamicForm/ModuleService.java create mode 100644 src/main/java/com/iemr/common/utils/exception/GlobalExceptionHandler.java create mode 100644 src/main/java/com/iemr/common/utils/response/ApiResponse.java diff --git a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java index f15ad2c0..a67dcadd 100644 --- a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java +++ b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java @@ -1,30 +1,96 @@ package com.iemr.common.controller.dynamicForm; -import com.iemr.common.data.dynamic_from.FormEntity; -import com.iemr.common.data.dynamic_from.ModuleEntity; -import com.iemr.common.dto.dynamicForm.FormTypeEntityDTO; -import com.iemr.common.dto.dynamicForm.ModuleEntityDTO; -import com.iemr.common.service.dynamicForm.FormTypeService; -import com.iemr.common.service.dynamicForm.ModuleService; +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.*; -@RequestMapping(value = "masterFrom") +import java.util.List; + +@RequestMapping(value = "dynamicForm",headers = "Authorization") @RestController public class DynamicFormController { - @Autowired ModuleService moduleService; @Autowired - private FormTypeService formTypeService; + 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("/modules") - public ResponseEntity createModule(@RequestBody ModuleEntityDTO module) { - return ResponseEntity.ok(moduleService.save(module)); + @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)); + } } - @PostMapping("/modules/{moduleId}/form-types") - public ResponseEntity createFormType(@PathVariable Long moduleId, @RequestBody FormTypeEntityDTO formType) { - return ResponseEntity.ok(formTypeService.createFormType(moduleId, formType)); + @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",headers = "Authorization") + 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/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/FormEntity.java b/src/main/java/com/iemr/common/data/dynamic_from/FormEntity.java deleted file mode 100644 index 578111f5..00000000 --- a/src/main/java/com/iemr/common/data/dynamic_from/FormEntity.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.iemr.common.data.dynamic_from; - -import com.fasterxml.jackson.annotation.JsonInclude; -import jakarta.persistence.*; -import lombok.Data; - -@Data -@Entity -@Table(name = "form_types",schema = "db_imer") -public class FormEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "Id") - private Long id; - - @Column(name = "form_name",columnDefinition = "TEXT") - private String formName; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "module_id") - private ModuleEntity module; - - @Column(name = "fields",columnDefinition = "TEXT") - private String fields ; - - -} 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/dynamic_from/ModuleEntity.java b/src/main/java/com/iemr/common/data/dynamic_from/ModuleEntity.java deleted file mode 100644 index 4d699a7e..00000000 --- a/src/main/java/com/iemr/common/data/dynamic_from/ModuleEntity.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.iemr.common.data.dynamic_from; - -import com.fasterxml.jackson.annotation.JsonInclude; -import jakarta.persistence.*; -import lombok.Data; - -import java.util.List; -@Data -@Entity -@Table(name = "m_modules",schema = "db_iemr") -public class ModuleEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "Id") - private Long id; - - @Column(name = "module_name",columnDefinition = "TEXT") - private String moduleName; - - @OneToMany(mappedBy = "module", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - private List formTypes; - -} 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/FormFieldDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FormFieldDTO.java deleted file mode 100644 index 27a6ee93..00000000 --- a/src/main/java/com/iemr/common/dto/dynamicForm/FormFieldDTO.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.iemr.common.dto.dynamicForm; - -import lombok.Data; - -import java.util.List; -import java.util.Map; - -@Data -public class FormFieldDTO { - private String name; - private String label; - private String type; - private boolean required; - private String inputType; - private String fileType; - private String buttonAction; - private String visibleIfField; - private String visibleIfValue; - private Map validations; - private List> options; - - // Getters and Setters -} 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/FormTypeEntityDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/FormTypeEntityDTO.java deleted file mode 100644 index ff31dfd5..00000000 --- a/src/main/java/com/iemr/common/dto/dynamicForm/FormTypeEntityDTO.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.iemr.common.dto.dynamicForm; - -import lombok.Data; - -import java.util.List; - -@Data -public class FormTypeEntityDTO { - - private Long id; - - private String formName; - - private ModuleEntityDTO module; - - private List fields; - -} 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/dynamicForm/ModuleEntityDTO.java b/src/main/java/com/iemr/common/dto/dynamicForm/ModuleEntityDTO.java deleted file mode 100644 index 03cfc834..00000000 --- a/src/main/java/com/iemr/common/dto/dynamicForm/ModuleEntityDTO.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.iemr.common.dto.dynamicForm; - -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; -@Data -public class ModuleEntityDTO { - private Long id; - private String moduleName; - -} 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/FormTypeRepository.java b/src/main/java/com/iemr/common/repository/dynamic_form/FormTypeRepository.java deleted file mode 100644 index b3b731fe..00000000 --- a/src/main/java/com/iemr/common/repository/dynamic_form/FormTypeRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.iemr.common.repository.dynamic_form; - -import com.iemr.common.data.dynamic_from.FormEntity; -import org.springframework.data.repository.CrudRepository; -import org.springframework.stereotype.Repository; - -@Repository -public interface FormTypeRepository extends CrudRepository {} 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 index e4eb221e..bafbfbea 100644 --- a/src/main/java/com/iemr/common/repository/dynamic_form/ModuleRepository.java +++ b/src/main/java/com/iemr/common/repository/dynamic_form/ModuleRepository.java @@ -1,10 +1,10 @@ package com.iemr.common.repository.dynamic_form; -import com.iemr.common.data.dynamic_from.ModuleEntity; +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 { +public interface ModuleRepository extends CrudRepository { } diff --git a/src/main/java/com/iemr/common/service/dynamicForm/FormMasterService.java b/src/main/java/com/iemr/common/service/dynamicForm/FormMasterService.java new file mode 100644 index 00000000..c603cd65 --- /dev/null +++ b/src/main/java/com/iemr/common/service/dynamicForm/FormMasterService.java @@ -0,0 +1,22 @@ +package com.iemr.common.service.dynamicForm; + +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.FieldDTO; +import com.iemr.common.dto.dynamicForm.FormDTO; +import com.iemr.common.dto.dynamicForm.FormResponseDTO; +import com.iemr.common.dto.dynamicForm.ModuleDTO; + +import java.util.List; + +public interface FormMasterService { + FormModule createModule(ModuleDTO dto); + FormDefinition createForm(FormDTO dto); + 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..893c1c8a --- /dev/null +++ b/src/main/java/com/iemr/common/service/dynamicForm/FormMasterServiceImpl.java @@ -0,0 +1,177 @@ +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()); + e.printStackTrace(); + 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/dynamicForm/FormTypeService.java b/src/main/java/com/iemr/common/service/dynamicForm/FormTypeService.java deleted file mode 100644 index 38068cdc..00000000 --- a/src/main/java/com/iemr/common/service/dynamicForm/FormTypeService.java +++ /dev/null @@ -1,35 +0,0 @@ -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.FormEntity; -import com.iemr.common.data.dynamic_from.ModuleEntity; -import com.iemr.common.dto.dynamicForm.FormTypeEntityDTO; -import com.iemr.common.repository.dynamic_form.FormTypeRepository; -import com.iemr.common.repository.dynamic_form.ModuleRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -@Service -public class FormTypeService { - @Autowired - ModuleRepository moduleRepo; - @Autowired - FormTypeRepository formTypeRepo; - @Autowired - ObjectMapper objectMapper; - - public FormEntity createFormType(Long moduleId, FormTypeEntityDTO formTypeDTO) { - ModuleEntity module = moduleRepo.findById(moduleId).orElseThrow(); - FormEntity formType = new FormEntity(); - formType.setFormName(formTypeDTO.getFormName()); - formType.setModule(module); - try { - String fieldsJson = objectMapper.writeValueAsString(formTypeDTO.getFields()); - formType.setFields(fieldsJson); - } catch (JsonProcessingException e) { - throw new RuntimeException("Failed to serialize form fields", e); - } - return formTypeRepo.save(formType); - } -} \ No newline at end of file diff --git a/src/main/java/com/iemr/common/service/dynamicForm/ModuleService.java b/src/main/java/com/iemr/common/service/dynamicForm/ModuleService.java deleted file mode 100644 index 644d2c59..00000000 --- a/src/main/java/com/iemr/common/service/dynamicForm/ModuleService.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.iemr.common.service.dynamicForm; - -import com.iemr.common.data.dynamic_from.ModuleEntity; -import com.iemr.common.dto.dynamicForm.ModuleEntityDTO; -import com.iemr.common.repository.dynamic_form.ModuleRepository; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.Optional; - -@Service -public class ModuleService { - @Autowired - ModuleRepository repo; - - public ModuleEntity save(ModuleEntityDTO module) { - ModuleEntity moduleEntity = new ModuleEntity(); - moduleEntity.setModuleName(module.getModuleName()); - return repo.save(moduleEntity); - } - - public Optional findById(Long id) { - return repo.findById(id); - } -} - 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..90a06c79 --- /dev/null +++ b/src/main/java/com/iemr/common/utils/exception/GlobalExceptionHandler.java @@ -0,0 +1,36 @@ +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) { + ex.printStackTrace(); // Log for debugging + 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/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 +} From 515f27ca449df8d8ec1a7256ac95c97b9bcde9d7 Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Jul 2025 10:25:10 +0530 Subject: [PATCH 14/16] dynamic from feature --- .../common/controller/dynamicForm/DynamicFormController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java index a67dcadd..065cdb14 100644 --- a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java +++ b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java @@ -93,4 +93,5 @@ public ResponseEntity> getStructuredForm(@PathVariable String for .body(ApiResponse.error("Failed to fetch form structure", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); } } + } From 27cf841f7216d0b3efb7de7dbacb13642578f3ae Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Jul 2025 10:25:25 +0530 Subject: [PATCH 15/16] dynamic from feature --- .../common/controller/dynamicForm/DynamicFormController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java index 065cdb14..a67dcadd 100644 --- a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java +++ b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java @@ -93,5 +93,4 @@ public ResponseEntity> getStructuredForm(@PathVariable String for .body(ApiResponse.error("Failed to fetch form structure", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); } } - } From 0e7b33b0e08c535cd7a90cded578b1dd6eaf04ed Mon Sep 17 00:00:00 2001 From: Saurav Mishra Date: Wed, 16 Jul 2025 10:26:35 +0530 Subject: [PATCH 16/16] dynamic from feature --- .../common/controller/dynamicForm/DynamicFormController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java index a67dcadd..065cdb14 100644 --- a/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java +++ b/src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java @@ -93,4 +93,5 @@ public ResponseEntity> getStructuredForm(@PathVariable String for .body(ApiResponse.error("Failed to fetch form structure", HttpStatus.INTERNAL_SERVER_ERROR.value(), null)); } } + }