Skip to content

fix: reject future dates in attendance regularization (#1340)#1408

Open
Xenon010101 wants to merge 3 commits into
Sachinchaurasiya360:mainfrom
Xenon010101:fix/future-date-check
Open

fix: reject future dates in attendance regularization (#1340)#1408
Xenon010101 wants to merge 3 commits into
Sachinchaurasiya360:mainfrom
Xenon010101:fix/future-date-check

Conversation

@Xenon010101
Copy link
Copy Markdown
Contributor

@Xenon010101 Xenon010101 commented Jun 4, 2026

fix: reject future dates in attendance regularization (#1340)

Description

Rejects attendance regularization requests where date, checkIn, or checkOut are in the future.

Changes

  • Added Zod .refine() to regularizeSchema: ensures date, checkIn, and checkOut are not in the future
  • Added runtime guard in regularize() service method
  • Prevents scheduling regularization for dates that haven't occurred yet

Testing

  • Future date → validation error
  • Future check-in time → validation error
  • Future check-out time → validation error
  • Past/present dates → proceeds as before

Closes #1340

Summary by CodeRabbit

  • Bug Fixes
    • Attendance regularization now rejects future dates and future check-in/check-out times, preventing future entries.
    • Validation runs earlier to catch timing issues before record persistence.
    • Error handling returns clear 400 responses for timing/validation failures instead of generic server errors.

…ya360#1340)

- Add Zod refinements to regularizeSchema: date, checkIn, checkOut
  must not be in the future
- Add runtime guards in regularize() service method
- Prevents regularization requests for dates/times that haven't
  occurred yet
@github-actions github-actions Bot added quality:clean Clean and well-structured contribution type:bug Bug fixes scope:backend Changes to server-side / API code labels Jun 4, 2026
@github-actions github-actions Bot added gssoc gssoc:approved Approved for GSSoC scoring labels Jun 4, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 4, 2026

Hi @Xenon010101, thanks for contributing to InternHack! 🎉

I have automatically:

  • 👤 Assigned this PR to you.
  • 🏷️ Applied the gssoc:approved label.

Our workflows will now analyze your changes to classify:

  • 📈 PR Difficulty: level:*
  • 🧩 PR Type: type:*
  • 🌟 PR Quality: quality:*

Tip

Ensure your PR description references the issue it resolves (e.g. Closes #123). This allows the bot to inherit any additional labels from that issue!

Happy coding! 🚀

@github-actions github-actions Bot added the level:beginner Good for first-time contributors label Jun 4, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR prevents regularizing future attendance data: Zod schema refinements disallow future date, checkIn, and checkOut, the service enforces the same runtime guards, and the controller returns 400 for those constraint errors.

Changes

Attendance Regularization Future Date Check

Layer / File(s) Summary
Schema future-timestamp refinements
server/src/module/attendance/attendance.validation.ts
regularizeSchema chains three .refine() rules that compare date, checkIn, and checkOut against the current/end-of-day and emit specific "cannot be in the future" messages.
Service guards and controller error mapping
server/src/module/attendance/attendance.service.ts, server/src/module/attendance/attendance.controller.ts
AttendanceService.regularize creates now and throws if date, checkIn, or checkOut are in the future before computing work hours or upserting. Controller regularize inspects Error messages and returns 400 for those constraint errors instead of a generic 500.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

Possibly related issues

  • #1340: fix: Missing Future Date Check in Attendance Regularization — Ensure regularization rejects future dates.

Suggested labels

bug

Suggested reviewers

  • Sachinchaurasiya360

Poem

🐰 I hop through code, a careful sniff and prance,
I block tomorrow's timestamps with a thump and dance.
No future check-ins can sneak past my sight,
Schema and service keep records honest and right.
Celebrate the fix — a carrot and a byte!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive All changes are narrowly scoped to attendance regularization validation; however, the brittle error message matching in the controller is fragile and could become a maintenance issue. Consider introducing a typed validation error class instead of error message substring matching to improve maintainability and reduce the risk of future regressions.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: rejecting future dates in attendance regularization, matching the primary objective and code changes.
Description check ✅ Passed The description includes key sections (Description, Changes, Testing, and linked issue) and clearly explains the fix, but lacks explicit Type of Change checkbox and Checklist completion.
Linked Issues check ✅ Passed The PR meets the core requirement of issue #1340 by adding validation to reject future dates, check-in, and check-out times in attendance regularization through both Zod schema and service-level guards.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
server/src/module/attendance/attendance.service.ts (1)

134-137: Note: Service validation errors are caught as HTTP 500 by the controller.

The runtime validation guards correctly throw errors when future dates are detected. However, per the context snippet in attendance.controller.ts:85-95, all service errors are caught and returned as HTTP 500 Internal Server Error. Validation failures like "Cannot regularize future dates" would be more semantically correct as HTTP 400 Bad Request.

This is a pre-existing controller behavior, not introduced by this PR. The service layer is correctly implementing business validation. Consider updating the controller in a future PR to distinguish validation errors from actual server errors.

🤖 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 `@server/src/module/attendance/attendance.service.ts` around lines 134 - 137,
The controller currently turns all thrown service errors into HTTP 500; update
attendance.controller.ts to return HTTP 400 for validation failures raised by
the service (e.g., the "Cannot regularize future dates" / "Check-in time cannot
be in the future" / "Check-out time cannot be in the future" errors thrown from
attendance.service.ts). Implement one of two approaches: (A) introduce a
specific ValidationError (or reuse Nest's BadRequestException) in
attendance.service.ts and throw that instead of generic Error, then in the
controller catch ValidationError/BadRequestException and respond with status
400, or (B) keep service throws but detect validation messages/types in
attendance.controller.ts and map them to a 400 response while other errors
remain 500; ensure you reference the controller method that calls the service
(the handler around lines 85–95) when making the change.
🤖 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.

Nitpick comments:
In `@server/src/module/attendance/attendance.service.ts`:
- Around line 134-137: The controller currently turns all thrown service errors
into HTTP 500; update attendance.controller.ts to return HTTP 400 for validation
failures raised by the service (e.g., the "Cannot regularize future dates" /
"Check-in time cannot be in the future" / "Check-out time cannot be in the
future" errors thrown from attendance.service.ts). Implement one of two
approaches: (A) introduce a specific ValidationError (or reuse Nest's
BadRequestException) in attendance.service.ts and throw that instead of generic
Error, then in the controller catch ValidationError/BadRequestException and
respond with status 400, or (B) keep service throws but detect validation
messages/types in attendance.controller.ts and map them to a 400 response while
other errors remain 500; ensure you reference the controller method that calls
the service (the handler around lines 85–95) when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: dedd1bfd-c081-418a-bfa5-c916930c8b2a

📥 Commits

Reviewing files that changed from the base of the PR and between e15a36c and d92d5da.

📒 Files selected for processing (2)
  • server/src/module/attendance/attendance.service.ts
  • server/src/module/attendance/attendance.validation.ts

- Map service validation errors (future dates, checkIn/checkOut)
  to HTTP 400 Bad Request instead of 500 Internal Server Error
@Sachinchaurasiya360
Copy link
Copy Markdown
Owner

Code Review — PR #1408: Reject future dates in attendance regularization

Hi @Xenon010101, adding future-date validation is the right fix. Found two issues with the implementation pattern.


🔴 Fragile error-message string matching in the controller

// attendance.controller.ts
if (msg.includes("must be after") || msg.includes("must not exceed") || msg.includes("Cannot regularize") || msg.includes("cannot be in the future"))
  return res.status(400).json({ message: msg });

This pattern is dangerous. The controller forwards a 400 only if the error message contains one of these hardcoded substrings. Problems:

  1. If anyone changes an error message string in the service (even a typo fix), the controller silently returns 500 instead of 400. The bug is invisible until a user reports a white screen.
  2. The substring list must be kept in sync with every validation message across the service — currently four strings, but this will grow.

Fix: Use a typed error class instead:

// attendance.errors.ts
export class AttendanceValidationError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "AttendanceValidationError";
  }
}

// attendance.service.ts
if (checkIn > now) throw new AttendanceValidationError("Check-in time cannot be in the future");

// attendance.controller.ts
} catch (error) {
  if (error instanceof AttendanceValidationError) {
    return res.status(400).json({ message: error.message });
  }
  console.error(error);
  return res.status(500).json({ message: "Internal Server Error" });
}

🟡 Future-date validation is duplicated between Zod schema and service layer

The Zod refine in attendance.validation.ts and the explicit if checks in attendance.service.ts both validate the same future-date rules. The Zod validation runs first (at the route boundary), so the service-level checks are never reached in practice.

The service-level checks are not wrong to have as a defense-in-depth guard, but they should match the Zod messages exactly (they don't — "Cannot regularize future dates" vs "Cannot regularize future dates" is fine, but "Check-in time cannot be in the future" vs the Zod message needs to be verified). Pick one canonical location and either remove the duplicates or keep them and accept they'll never fire in normal flow.

Copy link
Copy Markdown
Owner

@Sachinchaurasiya360 Sachinchaurasiya360 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Zod validation layer is a good addition and the intent is correct. Three issues need to be fixed before merge.

Bug 1 (Critical) - New service-layer guard is dead code with a divergent error message:

The PR adds an if (date > now) check in attendance.service.ts around line 135, but the pre-existing midnight-comparison guard at line 132 (if (date > today)) always fires first for any future date. The new guard is unreachable. Worse, its error message "Cannot regularize future dates" differs from the existing one "Cannot regularize attendance for future dates", so if the guard order ever changes, clients get inconsistent messages. Remove the new redundant guard from the service - Zod already handles this at the boundary, and the service already had its own guard.

Bug 2 (Critical) - False rejections for IST users:

The Zod refine in attendance.validation.ts compares checkIn and checkOut against new Date() (server UTC wall clock). For users in IST (UTC+5:30), a legitimate checkOut of 11:59 PM IST = 18:29 UTC. If they submit at 11:58 PM IST = 18:28 UTC, the server rejects with "Check-out time cannot be in the future" even though the time is in the past from the user perspective. The validation should compare within the context of the submitted date, not the raw UTC wall clock.

Bug 3 (Medium) - Phantom substring in controller catch block:

attendance.controller.ts has msg.includes("must not exceed") in the new catch logic, but this exact substring does not appear in any service throw in the codebase. It is a phantom check that never matches. This means if that error path is ever hit it silently becomes a 500. Use exact string equality checks (===) like the pattern already used for the checkOut handler in the same file.

Note: This PR and PR #1407 both modify the same regularize catch block in attendance.controller.ts. They will conflict when merged - please coordinate with the #1407 author or rebase onto whichever merges first.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@server/src/module/attendance/attendance.controller.ts`:
- Around line 93-97: Define a typed error class AttendanceValidationError in the
attendance service (e.g., export class AttendanceValidationError extends Error)
and update all service validation code (the places currently throwing new Error
for future dates, invalid times, regularize checks, etc.—e.g., the validation
branches used by checkIn/checkOut and other attendance service methods) to throw
AttendanceValidationError instead of plain Error; then change the controller's
error handling in attendance.controller.ts to check error instanceof
AttendanceValidationError and return res.status(400).json({ message:
error.message }) instead of relying on fragile substring matching.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7496215c-f1cd-4ca7-acff-63f95b2485d0

📥 Commits

Reviewing files that changed from the base of the PR and between d92d5da and 53b6303.

📒 Files selected for processing (2)
  • server/src/module/attendance/attendance.controller.ts
  • server/src/module/attendance/attendance.service.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/src/module/attendance/attendance.service.ts

Comment on lines +93 to +97
if (error instanceof Error) {
const msg = error.message;
if (msg.includes("must be after") || msg.includes("must not exceed") || msg.includes("Cannot regularize") || msg.includes("cannot be in the future"))
return res.status(400).json({ message: msg });
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Replace fragile string matching with typed error classes.

The reviewer (Sachinchaurasiya360) correctly identified that substring-based error routing is brittle and hard to maintain. If service error messages change, this controller logic may silently break, returning 500 instead of 400 for validation errors.

Additionally, this approach is inconsistent with other methods in this controller (checkIn and checkOut use exact string matching), making the error-handling strategy harder to understand and maintain.

Introduce a typed validation error class (e.g., AttendanceValidationError) in the service layer. Throw it for all validation failures (future dates, invalid times, etc.), then catch instanceof AttendanceValidationError here and return 400 with the error message. This eliminates string coupling and aligns with the reviewer's suggestion.

🏗️ Proposed refactor to use typed error class

First, define a validation error class in the service file:

// server/src/module/attendance/attendance.service.ts
export class AttendanceValidationError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'AttendanceValidationError';
  }
}

Then, in the service, replace throw new Error(...) with throw new AttendanceValidationError(...) for all validation failures (future dates, checkIn/checkOut constraints, etc.).

Finally, update the controller to catch the typed error:

     } catch (error) {
-      if (error instanceof Error) {
-        const msg = error.message;
-        if (msg.includes("must be after") || msg.includes("must not exceed") || msg.includes("Cannot regularize") || msg.includes("cannot be in the future"))
-          return res.status(400).json({ message: msg });
-      }
+      if (error instanceof AttendanceValidationError) {
+        return res.status(400).json({ message: error.message });
+      }
       console.error(error);
       return res.status(500).json({ message: "Internal Server Error" });
     }

As per coding guidelines, controller layer must handle request/response, call service, and format errors.

🤖 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 `@server/src/module/attendance/attendance.controller.ts` around lines 93 - 97,
Define a typed error class AttendanceValidationError in the attendance service
(e.g., export class AttendanceValidationError extends Error) and update all
service validation code (the places currently throwing new Error for future
dates, invalid times, regularize checks, etc.—e.g., the validation branches used
by checkIn/checkOut and other attendance service methods) to throw
AttendanceValidationError instead of plain Error; then change the controller's
error handling in attendance.controller.ts to check error instanceof
AttendanceValidationError and return res.status(400).json({ message:
error.message }) instead of relying on fragile substring matching.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved Approved for GSSoC scoring gssoc level:beginner Good for first-time contributors quality:clean Clean and well-structured contribution scope:backend Changes to server-side / API code type:bug Bug fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: Missing Future Date Check in Attendance Regularization

2 participants