Skip to content

Commit 231773e

Browse files
vanitha1822vishwab15Amoghsac2kadamSauravBizbRolly
authored
Merge Release-3.8.0 (3.6.1) to Main (#379)
* Move code to 3.6.1 to 3.8.0 (#372) * fix: cors spell fixes and import of packages updates * fix: deployment issue fix * feat: amm-1959 dhis token for cho report re-direction * fix: beneficiary history on revisit (#320) * fix: call type mapper (#322) * Elasticsearch implementation for Beneficiary Search (#324) * fix: implement functionality to search beneficiaries with Elasticsearch * fix: remove unwanted import * fix: update pom.xml * fix: change the response code * variable added * Elastic Search Implementation for Advanced Search (#327) * fix: cherry-pick commits for advanced search * fix: cherry-pick commit for token issue - mobile application * fix: add the missing properties * fix: add function to retrieve userid * fix: move the fetch Userid to jwtUtil * fix:signature check for mmu * fix: retrive any user without deleted * fix: update KM filepath * FLW-713 Remove All File Upload Options (#350) * FLW-713 Remove All File Upload Options * Fix UserServiceRoleRepo dependency issue and codeRabit comment * fixed coderabit comment * fix userMappingId issue * Add SMS functionality in release-3.6.1 (#358) * Enable SMS Functionality in MMU App to Send Prescriptions (#325) * fix: sms template save and map mmu (#306) * Vb/sms (#307) * fix: sms template save and map mmu * fix: enable mms for mmu prescription * Enable SMS Functionality in MMU App to Send Prescriptions (#325) * fix: sms template save and map mmu (#306) * Vb/sms (#307) * fix: sms template save and map mmu * fix: enable mms for mmu prescription --------- Co-authored-by: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> --------- Co-authored-by: 5Amogh <amoghavarsh@navadhiti.com> Co-authored-by: Vanitha S <116701245+vanitha1822@users.noreply.github.com> Co-authored-by: Sachin Kadam <152252767+sac2kadam@users.noreply.github.com> Co-authored-by: vanitha1822 <vanitha@navadhiti.com> Co-authored-by: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> * fix: add OTP rate limiting to prevent OTP flooding on sendConsent endpoint (#373) - Add OtpRateLimiterService with Redis-backed per-mobile rate limits (3/min, 10/hr, 20/day) - Add OtpRateLimitException for 429 responses - Integrate rate limiter in BeneficiaryOTPHandlerImpl and BeneficiaryConsentController - Add otp.ratelimit.* properties to common_ci and common_docker profiles - Update common_example.properties with new OTP rate limit config Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Health api (#376) * Cherry-pick health and version API enhancements to release-3.6.1 (#371) * feat(health,version): update version and health endpoints and add advance check for database * fix(health): normalize severity and fix slow query false positives * fix(health): avoid false CRITICAL on single long-running MySQL transaction * fix(health): enforce 3s DB connection timeout via HikariCP * Release 3.6.1 (#374) * feat(health,version): update version and health endpoints and add advance check for database * fix(health): normalize severity and fix slow query false positives * fix(health): avoid false CRITICAL on single long-running MySQL transaction * fix(health): enforce 3s DB connection timeout via HikariCP * feat(health): add healthcontroller and fix versioncontroller issues * fix: build error (#375) --------- Co-authored-by: KOPPIREDDY DURGA PRASAD <144464542+DurgaPrasad-54@users.noreply.github.com> Co-authored-by: Vanitha S <116701245+vanitha1822@users.noreply.github.com> --------- Co-authored-by: Vishwanath Balkur <118195001+vishwab1@users.noreply.github.com> Co-authored-by: 5Amogh <amoghavarsh@navadhiti.com> Co-authored-by: Sachin Kadam <152252767+sac2kadam@users.noreply.github.com> Co-authored-by: Saurav Mishra <80103738+SauravBizbRolly@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: KOPPIREDDY DURGA PRASAD <144464542+DurgaPrasad-54@users.noreply.github.com>
1 parent 4b44045 commit 231773e

33 files changed

+1233
-233
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"java.compile.nullAnalysis.mode": "automatic"
3+
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.iemr.common-API</groupId>
88
<artifactId>common-api</artifactId>
9-
<version>3.6.0</version>
9+
<version>3.8.0</version>
1010
<packaging>war</packaging>
1111

1212
<name>Common-API</name>

src/main/environment/common_ci.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ km-base-path=@env.KM_API_BASE_PATH@
1919
km-root-path=/okm:personal/users/
2020
km-guest-user=@env.KM_GUEST_USER@
2121
km-guest-password=@env.KM_GUEST_PASSWORD@
22+
tempFilePath=@env.TEMP_FILE_PATH@
2223

2324
# CTI Config
2425
cti-server-ip=@env.CTI_SERVER_IP@
@@ -202,5 +203,9 @@ platform.feedback.ratelimit.day-limit=@env.PLATFORM_FEEDBACK_RATELIMIT_DAY_LIMIT
202203
platform.feedback.ratelimit.user-day-limit=@env.PLATFORM_FEEDBACK_RATELIMIT_USER_DAY_LIMIT@
203204
platform.feedback.ratelimit.fail-window-minutes=@env.PLATFORM_FEEDBACK_RATELIMIT_FAIL_WINDOW_MINUTES@
204205
platform.feedback.ratelimit.backoff-minutes=@env.PLATFORM_FEEDBACK_RATELIMIT_BACKOFF_MINUTES@
206+
otp.ratelimit.enabled=@env.OTP_RATELIMIT_ENABLED@
207+
otp.ratelimit.minute-limit=@env.OTP_RATELIMIT_MINUTE_LIMIT@
208+
otp.ratelimit.hour-limit=@env.OTP_RATELIMIT_HOUR_LIMIT@
209+
otp.ratelimit.day-limit=@env.OTP_RATELIMIT_DAY_LIMIT@
205210
generateBeneficiaryIDs-api-url=@env.GEN_BENEFICIARY_IDS_API_URL@
206211

src/main/environment/common_docker.properties

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ everwellRegisterBenficiary = ${COMMON_API_BASE_URL}/beneficiary/create
126126
## LungAssessment credentials
127127
lungAssessmentEmail = ${SWAASA_EMAIL}
128128
lungAssessmentPassword =${SWAASA_PASSWORD}
129-
129+
tempFilePath=${TEMP_FILE_PATH}
130130

131131
## SWASSA APIs
132132
lungAssessmentAdminLogin = ${SWAASA_BASE_URL}/api/adminLogin
@@ -206,4 +206,8 @@ platform.feedback.ratelimit.day-limit=${PLATFORM_FEEDBACK_RATELIMIT_DAY_LIMIT}
206206
platform.feedback.ratelimit.user-day-limit=${PLATFORM_FEEDBACK_RATELIMIT_USER_DAY_LIMIT}
207207
platform.feedback.ratelimit.fail-window-minutes=${PLATFORM_FEEDBACK_RATELIMIT_FAIL_WINDOW_MINUTES}
208208
platform.feedback.ratelimit.backoff-minutes=${PLATFORM_FEEDBACK_RATELIMIT_BACKOFF_MINUTES}
209+
otp.ratelimit.enabled=${OTP_RATELIMIT_ENABLED}
210+
otp.ratelimit.minute-limit=${OTP_RATELIMIT_MINUTE_LIMIT}
211+
otp.ratelimit.hour-limit=${OTP_RATELIMIT_HOUR_LIMIT}
212+
otp.ratelimit.day-limit=${OTP_RATELIMIT_DAY_LIMIT}
209213
generateBeneficiaryIDs-api-url={GEN_BENEFICIARY_IDS_API_URL}

src/main/environment/common_example.properties

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ km-root-path=/okm:personal/users/
2525
km-guest-user=guest
2626
km-guest-password=guest
2727

28+
tempFilePath=/opt/openkm
29+
2830
# CTI Config
2931
cti-server-ip=10.208.122.99
3032
cti-logger_base_url=http://10.208.122.99/logger
@@ -224,5 +226,10 @@ platform.feedback.ratelimit.user-day-limit=50
224226
platform.feedback.ratelimit.fail-window-minutes=5
225227
platform.feedback.ratelimit.backoff-minutes=15
226228

229+
# --- OTP Rate Limiting (per mobile number) ---
230+
otp.ratelimit.minute-limit=3
231+
otp.ratelimit.hour-limit=10
232+
otp.ratelimit.day-limit=20
233+
227234
### generate Beneficiary IDs URL
228235
generateBeneficiaryIDs-api-url=/generateBeneficiaryController/generateBeneficiaryIDs

src/main/java/com/iemr/common/controller/beneficiary/BeneficiaryRegistrationController.java

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.slf4j.LoggerFactory;
3737
import org.springframework.beans.factory.annotation.Autowired;
3838
import org.springframework.web.bind.annotation.RequestBody;
39+
import org.springframework.web.bind.annotation.RequestHeader;
3940
import org.springframework.web.bind.annotation.RequestMapping;
4041
import org.springframework.web.bind.annotation.RequestMethod;
4142
import org.springframework.web.bind.annotation.RestController;
@@ -71,6 +72,8 @@
7172
import com.iemr.common.service.userbeneficiarydata.MaritalStatusService;
7273
import com.iemr.common.service.userbeneficiarydata.StatusService;
7374
import com.iemr.common.service.userbeneficiarydata.TitleService;
75+
import com.iemr.common.utils.CookieUtil;
76+
import com.iemr.common.utils.JwtUtil;
7477
import com.iemr.common.utils.mapper.InputMapper;
7578
import com.iemr.common.utils.mapper.OutputMapper;
7679
import com.iemr.common.utils.response.OutputResponse;
@@ -105,6 +108,8 @@ public class BeneficiaryRegistrationController {
105108
private BeneficiaryOccupationService beneficiaryOccupationService;
106109
private GovtIdentityTypeService govtIdentityTypeService;
107110

111+
@Autowired
112+
private JwtUtil jwtUtil;
108113

109114
@Autowired
110115
public void setBenRelationshipTypeService(BenRelationshipTypeService benRelationshipTypeService) {
@@ -344,6 +349,54 @@ public String searchUserByPhone(
344349
return response.toString();
345350
}
346351

352+
@Operation(summary = "Provide the list of beneficiaries using Elasticsearch")
353+
@RequestMapping(value = "/searchUser", method = RequestMethod.POST, headers = "Authorization")
354+
public String searchUser(@RequestBody String request, HttpServletRequest httpRequest) {
355+
OutputResponse response = new OutputResponse();
356+
try {
357+
logger.info("Universal search request received");
358+
359+
JsonParser parser = new JsonParser();
360+
JsonObject requestObj = parser.parse(request).getAsJsonObject();
361+
362+
String searchQuery = null;
363+
if (requestObj.has("search") && !requestObj.get("search").isJsonNull()) {
364+
searchQuery = requestObj.get("search").getAsString();
365+
}
366+
367+
if (searchQuery == null || searchQuery.trim().isEmpty()) {
368+
response.setError(400, "Search query is required");
369+
return response.toString();
370+
}
371+
372+
String auth = httpRequest.getHeader("Authorization");
373+
374+
Integer userID = jwtUtil.getUserIdFromRequest(httpRequest);
375+
376+
logger.info("ES search for userId: {}", userID);
377+
378+
Boolean is1097 = false;
379+
if (requestObj.has("is1097") && !requestObj.get("is1097").isJsonNull()) {
380+
is1097 = requestObj.get("is1097").getAsBoolean();
381+
}
382+
383+
logger.info("Searching with query: {}, userId: {}, is1097: {}", searchQuery, userID, is1097);
384+
String result = iemrSearchUserService.searchUser(searchQuery, userID, auth, is1097);
385+
386+
if (result == null || result.trim().isEmpty()) {
387+
response.setError(200, "No beneficiaries found");
388+
return response.toString();
389+
}
390+
391+
return result;
392+
393+
} catch (Exception e) {
394+
logger.error("Error in universal search: {}", e.getMessage(), e);
395+
response.setError(400, "Error searching beneficiaries: " + e.getMessage());
396+
return response.toString();
397+
}
398+
}
399+
347400
@Operation(summary = "Provide the list of beneficiaries based on search criteria")
348401
@RequestMapping(value = "/searchBeneficiary", method = RequestMethod.POST, headers = "Authorization")
349402
public String searchBeneficiary(
@@ -366,6 +419,41 @@ public String searchBeneficiary(
366419
return output.toString();
367420
}
368421

422+
/**
423+
* Elasticsearch-based advanced search endpoint
424+
*/
425+
@Operation(summary = "Advanced search beneficiaries using Elasticsearch")
426+
@RequestMapping(value = "/searchBeneficiaryES", method = RequestMethod.POST, headers = "Authorization")
427+
public String searchBeneficiaryES(
428+
@RequestBody BeneficiaryModel request,
429+
HttpServletRequest httpRequest) {
430+
431+
logger.info("searchBeneficiaryES request: {}", request);
432+
OutputResponse output = new OutputResponse();
433+
434+
try {
435+
436+
String auth = httpRequest.getHeader("Authorization");
437+
438+
Integer userID = jwtUtil.getUserIdFromRequest(httpRequest);
439+
440+
logger.info("ES Advanced search for userId: {}", userID);
441+
442+
String result = iemrSearchUserService.findBeneficiaryES(request, userID, auth);
443+
444+
return result;
445+
446+
} catch (NumberFormatException ne) {
447+
logger.error("searchBeneficiaryES failed with number format error: {}", ne.getMessage(), ne);
448+
output.setError(400, "Invalid number format in search criteria");
449+
return output.toString();
450+
} catch (Exception e) {
451+
logger.error("searchBeneficiaryES failed with error: {}", e.getMessage(), e);
452+
output.setError(500, "Error searching beneficiaries: " + e.getMessage());
453+
return output.toString();
454+
}
455+
}
456+
369457
@Operation(summary = "Provide all common data list needed for beneficiary registration")
370458
@RequestMapping(value = "/getRegistrationData", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON, headers = "Authorization")
371459
public String getRegistrationData() {

src/main/java/com/iemr/common/controller/beneficiaryConsent/BeneficiaryConsentController.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
package com.iemr.common.controller.beneficiaryConsent;
2323

2424
import com.iemr.common.data.beneficiaryConsent.BeneficiaryConsentRequest;
25+
import com.iemr.common.exception.OtpRateLimitException;
2526
import com.iemr.common.service.beneficiaryOTPHandler.BeneficiaryOTPHandler;
2627
import com.iemr.common.utils.mapper.InputMapper;
2728
import com.iemr.common.utils.response.OutputResponse;
@@ -58,7 +59,9 @@ public String sendConsent(@Param(value = "{\"mobNo\":\"String\"}") @RequestBody
5859
logger.info(success.toString());
5960
response.setResponse(success);
6061

61-
62+
} catch (OtpRateLimitException e) {
63+
logger.warn("OTP rate limit hit for sendConsent: " + e.getMessage());
64+
response.setError(429, e.getMessage());
6265
} catch (Exception e) {
6366
response.setError(500, "error : " + e);
6467
}
@@ -105,6 +108,9 @@ public String resendConsent(@Param(value = "{\"mobNo\":\"String\"}") @RequestBod
105108
else
106109
response.setError(500, "failure");
107110

111+
} catch (OtpRateLimitException e) {
112+
logger.warn("OTP rate limit hit for resendConsent: " + e.getMessage());
113+
response.setError(429, e.getMessage());
108114
} catch (Exception e) {
109115
logger.error("error in re-sending Consent : " + e);
110116
response.setError(500, "error : " + e);

src/main/java/com/iemr/common/controller/dynamicForm/DynamicFormController.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,9 @@ public ResponseEntity<ApiResponse<?>> deleteField(@PathVariable Long fieldId) {
8484
}
8585

8686
@GetMapping(value = "form/{formId}/fields")
87-
public ResponseEntity<ApiResponse<?>> getStructuredForm(@PathVariable String formId, @RequestParam(name = "lang", defaultValue = "en") String lang) {
87+
public ResponseEntity<ApiResponse<?>> getStructuredForm(@PathVariable String formId, @RequestParam(name = "lang", defaultValue = "en") String lang,@RequestHeader(value = "jwttoken") String token) {
8888
try {
89-
Object result = formMasterService.getStructuredFormByFormId(formId,lang);
89+
Object result = formMasterService.getStructuredFormByFormId(formId,lang,token);
9090
return ResponseEntity.status(HttpStatus.OK)
9191
.body(ApiResponse.success("Form structure fetched successfully", HttpStatus.OK.value(), result));
9292
} catch (Exception e) {

src/main/java/com/iemr/common/controller/users/IEMRAdminController.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1224,7 +1224,25 @@ public ResponseEntity<?> getUserDetails(@PathVariable("userName") String userNam
12241224
return new ResponseEntity<>(Map.of("error", "UserName Not Found"), HttpStatus.NOT_FOUND);
12251225
}
12261226
User user = users.get(0);
1227-
return new ResponseEntity<>(Map.of("userName", user.getUserName(), "userId", user.getUserID()), HttpStatus.OK);
1227+
return new ResponseEntity<>(Map.of("userName", user.getUserName(), "userId", user.getUserID()),
1228+
HttpStatus.OK);
1229+
} catch (Exception e) {
1230+
return new ResponseEntity<>(Map.of("error", "Internal server error"), HttpStatus.INTERNAL_SERVER_ERROR);
1231+
}
1232+
1233+
}
1234+
1235+
@Operation(summary = "Get UserId based on userName")
1236+
@GetMapping(value = "/checkUserName/{userName}", produces = MediaType.APPLICATION_JSON, headers = "Authorization")
1237+
public ResponseEntity<?> checkUserDetails(@PathVariable("userName") String userName) {
1238+
try {
1239+
List<User> users = iemrAdminUserServiceImpl.findUserIdByUserName(userName);
1240+
if (users.isEmpty()) {
1241+
return new ResponseEntity<>(Map.of("error", "UserName Not Found"), HttpStatus.NOT_FOUND);
1242+
}
1243+
User user = users.get(0);
1244+
return new ResponseEntity<>(Map.of("userName", user.getUserName(), "userId", user.getUserID()),
1245+
HttpStatus.OK);
12281246
} catch (Exception e) {
12291247
return new ResponseEntity<>(Map.of("error", "Internal server error"), HttpStatus.INTERNAL_SERVER_ERROR);
12301248
}

src/main/java/com/iemr/common/controller/version/VersionController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,4 @@ private Properties loadGitProperties() throws IOException {
8585
}
8686
return properties;
8787
}
88-
}
88+
}

0 commit comments

Comments
 (0)