fix: resolve 5 bugs in scheduling, specialist, JWT, and config layers#69
fix: resolve 5 bugs in scheduling, specialist, JWT, and config layers#69PragyaTripathi990 wants to merge 1 commit intoPSMRI:mainfrom
Conversation
WalkthroughThis PR introduces timezone-aware date handling and transactional semantics in the scheduling service, relaxes token invalidation error handling, corrects a configuration property reference, and adds defensive validation for specialist query results across four independent services. ChangesScheduling Service Timezone & Transactional Enhancement
Service Fixes & Configuration Corrections
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- SchedulingServiceImpl: replace IntStream.forEach lambda that silently swallowed TMException with a plain for-loop so checked exceptions propagate correctly; add @transactional so partial DB writes on error are rolled back atomically - SchedulingServiceImpl: replace deprecated Timestamp.getHours()/ getMinutes() with toLocalDateTime().toLocalTime() to avoid timezone-sensitive slot index miscalculations; replace deprecated new Date(year,month,date) constructors with LocalDate + ZoneId - SpecialistServiceImpl.getAllSpecialist: add action.length < 7 bounds guard before accessing action[6] to prevent ArrayIndexOutOfBounds when the query returns fewer columns than expected - JwtUtil.invalidateToken: remove RuntimeException rethrow in catch block; an already-expired/invalid token is a no-op, not an error — prevents HTTP 500 on logout with expired tokens - ConfigProperties.getExtendExpiryTime: fix wrong property key from "iemr.session.expiry.time" (numeric) to "iemr.extend.expiry.time" (boolean) so session extension actually reads the correct config flag
29dc94b to
7d4cad6
Compare
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java (1)
158-159:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDay-span calculation is DST-sensitive and can skip/duplicate dates.
(endDate.getTime() - startDate.getTime()) / 86400000is not stable across DST transitions, so loop bounds can be wrong. UseLocalDate+ChronoUnit.DAYSand iterate date objects directly.Suggested fix
+import java.time.temporal.ChronoUnit; ... - Integer durationDays = (int) ((endDate.getTime() - startDate.getTime()) / 86400000); + LocalDate startLocalDate = LocalDate.ofInstant(startDate.toInstant(), ZoneId.systemDefault()); + LocalDate endLocalDate = LocalDate.ofInstant(endDate.toInstant(), ZoneId.systemDefault()); + long durationDays = ChronoUnit.DAYS.between(startLocalDate, endLocalDate); ... - for (int e = 0; e <= durationDays; e++) { - Date i = new Date(startDate.getTime()); - i.setDate(i.getDate() + e); - Integer day = i.getDay(); + for (long e = 0; e <= durationDays; e++) { + LocalDate d = startLocalDate.plusDays(e); + Date i = Date.from(d.atStartOfDay(ZoneId.systemDefault()).toInstant()); + Integer day = i.getDay();Also applies to: 182-185
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java` around lines 158 - 159, The current day-span calculation using Integer durationDays = (int) ((endDate.getTime() - startDate.getTime()) / 86400000) is DST-sensitive and can produce wrong loop bounds; update SchedulingServiceImpl to convert the Date objects (startDate, endDate) to java.time.LocalDate and compute the span with java.time.temporal.ChronoUnit.DAYS (or iterate from startLocalDate to endLocalDate using LocalDate.plusDays()) when building the loop that currently uses durationDays; replace both the occurrence around the durationDays variable and the similar logic at the later block (lines referenced 182-185) to operate on LocalDate instances rather than millis arithmetic so iteration is stable across DST transitions.
🧹 Nitpick comments (2)
src/main/java/com/iemr/tm/utils/JwtUtil.java (1)
65-67: 💤 Low valueLGTM - logout gracefully handles invalid tokens.
The silent success on exception is correct behavior for logout endpoints. When a token is already expired or malformed, attempting to invalidate it should not fail.
Optional improvement: consider adding debug-level logging to aid troubleshooting:
🔍 Optional logging enhancement
} catch (Exception e) { // Token is already expired or invalid — nothing to denylist, treat as success + logger.debug("Token invalidation skipped (already expired/invalid): {}", e.getMessage()); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/iemr/tm/utils/JwtUtil.java` around lines 65 - 67, The catch block in JwtUtil that swallows exceptions during token invalidation should remain silent for correctness but add a debug-level log to aid troubleshooting; inside the catch (Exception e) in JwtUtil (the logout/token invalidation method), call the class logger at debug/trace level including a short message and e.getMessage()/exception to record expired/malformed tokens without changing behavior or returning an error.src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java (1)
55-66: ⚡ Quick winConsider adding similar bounds checking to
getspecialistUserfor consistency.The
getspecialistUsermethod accesses array indices 0-10 without bounds validation, whilegetAllSpecialistnow has defensive checks. If the repository can return malformed data in one method, it may also occur in the other.🛡️ Proposed fix to add bounds checking
if (obj.size() > 0) { for (Object[] action : obj) { + if (action.length < 11) { + logger.warn("Skipping malformed specialist row with {} columns (expected 11) for specializationID: {}, parkingPlaceID: {}", + action.length, specializationID, parkingplaceID); + continue; + } specialistList.add(new Specialist((String) action[0], ((Number) action[1]).longValue(), (String) action[2], (String) action[3], (String) action[4], ((Number) action[5]).longValue(), (String) action[6], (String) action[7], (String) action[8], (String) action[9], (String) action[10]));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java` around lines 55 - 66, In SpecialistServiceImpl, update the getspecialistUser method to mirror the defensive checks used in the getspecialistSP handling: ensure the returned List<Object[]> (from specializationRepo.getspecialistUser) is not null/empty and for each Object[] verify its length is at least 11 before indexing; when a row is malformed skip it (or log a warning) and only construct new Specialist instances after safely casting numeric fields using ((Number) action[index]).longValue() and string fields with (String) action[index].
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java`:
- Around line 97-103: In SchedulingServiceImpl, validate the computed slot
window before calling slotdetail.substring: after computing startLocal,
endLocal, startslot and endslot, check that startslot < endslot, both are >= 0,
and endslot <= slotdetail.length(); if any of these checks fail throw a
TMException with a clear message (e.g., "Invalid slot window: startslot X
endslot Y for slotdetail length Z") instead of allowing
StringIndexOutOfBoundsException; update the code paths that use
startslot/endslot (the substring call referencing slotdetail) to rely on this
validation.
In `@src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java`:
- Line 76: Replace the silent skip of malformed CSV/array rows in
SpecialistServiceImpl by logging the skipped row for troubleshooting: when you
encounter the check if (action.length < 7) in the method that processes "action"
entries, emit a warning (e.g., logger.warn) that includes the row contents
(Arrays.toString(action) or similar) and any context (e.g., patientId or loop
index if available) before continuing, so malformed data is recorded for later
diagnosis.
---
Outside diff comments:
In `@src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java`:
- Around line 158-159: The current day-span calculation using Integer
durationDays = (int) ((endDate.getTime() - startDate.getTime()) / 86400000) is
DST-sensitive and can produce wrong loop bounds; update SchedulingServiceImpl to
convert the Date objects (startDate, endDate) to java.time.LocalDate and compute
the span with java.time.temporal.ChronoUnit.DAYS (or iterate from startLocalDate
to endLocalDate using LocalDate.plusDays()) when building the loop that
currently uses durationDays; replace both the occurrence around the durationDays
variable and the similar logic at the later block (lines referenced 182-185) to
operate on LocalDate instances rather than millis arithmetic so iteration is
stable across DST transitions.
---
Nitpick comments:
In `@src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java`:
- Around line 55-66: In SpecialistServiceImpl, update the getspecialistUser
method to mirror the defensive checks used in the getspecialistSP handling:
ensure the returned List<Object[]> (from specializationRepo.getspecialistUser)
is not null/empty and for each Object[] verify its length is at least 11 before
indexing; when a row is malformed skip it (or log a warning) and only construct
new Specialist instances after safely casting numeric fields using ((Number)
action[index]).longValue() and string fields with (String) action[index].
In `@src/main/java/com/iemr/tm/utils/JwtUtil.java`:
- Around line 65-67: The catch block in JwtUtil that swallows exceptions during
token invalidation should remain silent for correctness but add a debug-level
log to aid troubleshooting; inside the catch (Exception e) in JwtUtil (the
logout/token invalidation method), call the class logger at debug/trace level
including a short message and e.getMessage()/exception to record
expired/malformed tokens without changing behavior or returning an error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 9fa07d03-e758-4aba-bf8d-c7f868b0eada
📒 Files selected for processing (4)
src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.javasrc/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.javasrc/main/java/com/iemr/tm/utils/JwtUtil.javasrc/main/java/com/iemr/tm/utils/config/ConfigProperties.java
| LocalTime startLocal = startTime.toLocalDateTime().toLocalTime(); | ||
| LocalTime endLocal = endTime.toLocalDateTime().toLocalTime(); | ||
| Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5; | ||
| Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5; | ||
|
|
||
| String currentstatus = slotdetail.substring(startslot, endslot); | ||
|
|
There was a problem hiding this comment.
Add explicit slot-window validation before substring access.
substring(startslot, endslot) can throw runtime exceptions when input times are inverted/equal or out of day bounds. Fail fast with TMException instead of bubbling StringIndexOutOfBoundsException.
Suggested fix
Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5;
Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5;
+ if (startslot < 0 || endslot > slotdetail.length() || endslot <= startslot) {
+ throw new TMException("Invalid slot time range");
+ }
String currentstatus = slotdetail.substring(startslot, endslot);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| LocalTime startLocal = startTime.toLocalDateTime().toLocalTime(); | |
| LocalTime endLocal = endTime.toLocalDateTime().toLocalTime(); | |
| Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5; | |
| Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5; | |
| String currentstatus = slotdetail.substring(startslot, endslot); | |
| LocalTime startLocal = startTime.toLocalDateTime().toLocalTime(); | |
| LocalTime endLocal = endTime.toLocalDateTime().toLocalTime(); | |
| Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5; | |
| Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5; | |
| if (startslot < 0 || endslot > slotdetail.length() || endslot <= startslot) { | |
| throw new TMException("Invalid slot time range"); | |
| } | |
| String currentstatus = slotdetail.substring(startslot, endslot); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java` around
lines 97 - 103, In SchedulingServiceImpl, validate the computed slot window
before calling slotdetail.substring: after computing startLocal, endLocal,
startslot and endslot, check that startslot < endslot, both are >= 0, and
endslot <= slotdetail.length(); if any of these checks fail throw a TMException
with a clear message (e.g., "Invalid slot window: startslot X endslot Y for
slotdetail length Z") instead of allowing StringIndexOutOfBoundsException;
update the code paths that use startslot/endslot (the substring call referencing
slotdetail) to rely on this validation.
| List<Object[]> obj = specializationRepo.getAllSPecialistForProvider(providerservicemapID); | ||
| if (obj.size() > 0) { | ||
| for (Object[] action : obj) { | ||
| if (action.length < 7) continue; |
There was a problem hiding this comment.
Log skipped rows for troubleshooting data quality issues.
Silently skipping malformed rows without logging makes it difficult to detect and diagnose data quality issues or potential query bugs in production.
📝 Proposed fix to add logging
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
`@Service`
public class SpecialistServiceImpl implements SpecialistService {
+
+ private static final Logger logger = LoggerFactory.getLogger(SpecialistServiceImpl.class);
`@Autowired`
SpecializationRepo specializationRepo;Then update the check:
for (Object[] action : obj) {
- if (action.length < 7) continue;
+ if (action.length < 7) {
+ logger.warn("Skipping malformed specialist row with {} columns (expected 7) for providerServiceMapID: {}",
+ action.length, providerservicemapID);
+ continue;
+ }
specialistList.add(new Specialist(null, ((Number) action[0]).longValue(), (String) action[1],📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (action.length < 7) continue; | |
| import org.slf4j.Logger; | |
| import org.slf4j.LoggerFactory; |
| if (action.length < 7) continue; | |
| `@Service` | |
| public class SpecialistServiceImpl implements SpecialistService { | |
| private static final Logger logger = LoggerFactory.getLogger(SpecialistServiceImpl.class); | |
| `@Autowired` | |
| SpecializationRepo specializationRepo; |
| if (action.length < 7) continue; | |
| for (Object[] action : obj) { | |
| if (action.length < 7) { | |
| logger.warn("Skipping malformed specialist row with {} columns (expected 7) for providerServiceMapID: {}", | |
| action.length, providerservicemapID); | |
| continue; | |
| } | |
| specialistList.add(new Specialist(null, ((Number) action[0]).longValue(), (String) action[1], |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java` at
line 76, Replace the silent skip of malformed CSV/array rows in
SpecialistServiceImpl by logging the skipped row for troubleshooting: when you
encounter the check if (action.length < 7) in the method that processes "action"
entries, emit a warning (e.g., logger.warn) that includes the row contents
(Arrays.toString(action) or similar) and any context (e.g., patientId or loop
index if available) before continuing, so malformed data is recorded for later
diagnosis.



Summary
TMExceptioninSchedulingServiceImpl— replacedIntStream.forEachlambda with a plainforloop so exceptions propagate; added@Transactional(rollbackFor = TMException.class)for atomicityDateAPIs — replacedTimestamp.getHours()/getMinutes()withtoLocalDateTime().toLocalTime()and deprecatednew Date(year, month, date)constructors withLocalDate.ofInstant(..., ZoneId.systemDefault())ArrayIndexOutOfBoundsExceptionrisk inSpecialistServiceImpl.getAllSpecialist— added bounds guard before accessingaction[6]JwtUtil.invalidateToken— removed erroneousRuntimeExceptionrethrow in catch blockConfigProperties.getExtendExpiryTime— changed from"iemr.session.expiry.time"(integer) to"iemr.extend.expiry.time"(boolean) so session extension config is read correctlyTest plan
markAvailabilitywith a date range: verifyTMExceptionon a conflict rolls back all insertsgetAllSpecialistreturns results withoutArrayIndexOutOfBoundsExceptioniemr.extend.expiry.time=truecausesgetExtendExpiryTime()to returntrueSummary by CodeRabbit
Bug Fixes
Refactor