Skip to content

Fix idle 7 days + calculation logic#2584

Merged
prakashchoudhary07 merged 15 commits intodevelopfrom
fix/idle-7day+
Mar 18, 2026
Merged

Fix idle 7 days + calculation logic#2584
prakashchoudhary07 merged 15 commits intodevelopfrom
fix/idle-7day+

Conversation

@vinit717
Copy link
Copy Markdown
Member

@vinit717 vinit717 commented Feb 26, 2026

Date: 27-02-2026

Developer Name: @vinit717


Issue Ticket Number

Description

Fix the 7-day+ idle users calculation logic

CRON JOB START: Fetch all users where currentStatus.state == IDLE
  │
  ▼
FOR EACH USER: Determine Window Start
  ├─ If `idleWindowStartedAt` exists ──► windowStart = idleWindowStartedAt
  └─ If missing (fallback) ────────────► windowStart = currentStatus.from
  │
  ▼
FETCH SOURCE OF TRUTH OOO DATA
  ├─ Query Firestore `requests` collection:
  │    WHERE requestedBy == "user-id" 
  │      AND type == "OOO" 
  │      AND status (or state) == "APPROVED"
  │
  ▼
PROCESS OOO PERIODS
  ├─ 1. Filter out requests that happened before `windowStart`
  ├─ 2. Merge overlapping timestamps (e.g., 2 consecutive requests become 1 block)
  └─ Result = [Clean list of valid OOO date ranges]
  │
  ▼
CALCULATE IDLE DAYS
  ├─ Total calendar days = (Date.now() - windowStart)
  ├─ Approved OOO days = Sum of the merged OOO date ranges
  ├─ Net Idle Days = (Total calendar days) - (Approved OOO days)
  │
  ▼
APPLY OR REMOVE ROLE
  ├─ IF Net Idle Days >= 7:
  │    └─ Add `group-idle-7d+` Discord role
  ├─ ELSE:
  │    └─ Remove `group-idle-7d+` Discord role (if they currently hold it)

Documentation Updated?

  • Yes
  • No

Under Feature Flag

  • Yes
  • No

Database Changes

  • Yes
  • No

Breaking Changes

  • Yes
  • No

Development Tested?

  • Yes
  • No

Screenshots

image

Test Coverage

Screenshot 2026-03-02 at 6 29 43 PM

Additional Notes

@vinit717 vinit717 marked this pull request as draft February 26, 2026 06:19
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 26, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 15a3afb7-58ba-494b-86aa-fe82f142cf19

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

The PR introduces a utility function computeIdleDaysExcludingOOO that calculates idle days while excluding out-of-office periods. It updates idle-user detection in discordactions.js to use this function and refines userStatus.js to consistently track idle window start times and OOO period boundaries across status transitions.

Changes

Cohort / File(s) Summary
Idle Calculation Utility
utils/userStatus.js
Adds computeIdleDaysExcludingOOO function to compute idle days within a time window, excluding overlap with the last OOO period. Uses idleWindowStartedAt or currentStatus.from as fallback for window start.
Discord Idle Detection
models/discordactions.js
Updates updateIdle7dUsersOnDiscord to use computeIdleDaysExcludingOOO for determining idle status. Now fetches and evaluates computed idle days instead of manual calculation. Enhances error logging for discordId updates.
User Status Tracking
models/userStatus.js
Consistently populates lastOooFrom from previous status when updating OOO periods. Sets idleWindowStartedAt when transitioning to IDLE state. Applies these updates across new user creation, batch updates, and OOO cancellation paths.
Utility Tests
test/unit/utils/userStatus.test.js
Adds test suite for computeIdleDaysExcludingOOO with four test cases covering idle calculation with and without OOO periods, fallback behavior, and edge cases.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • AnujChhikara
  • iamitprakash
  • prakashchoudhary07

Poem

🐰 A rabbit hops through status fields with glee,
Idle days now counted, OOO-free!
With windows started and timestamps bound,
Users' true rest periods are finally found. 🌙

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: fixing the idle 7 days+ calculation logic, which is directly reflected in the changes to discordactions.js, userStatus.js, and the new computeIdleDaysExcludingOOO utility function.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The pull request description clearly describes the fix for the 7-day+ idle users calculation logic with detailed pseudocode, architectural decisions, and implementation details that align with the file changes.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/idle-7day+
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@vinit717 vinit717 self-assigned this Feb 28, 2026
@vinit717 vinit717 marked this pull request as ready for review February 28, 2026 13:15
Copy link
Copy Markdown

@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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@models/discordactions.js`:
- Around line 696-697: The current conditional in the idle-days check (if
(idleDays <= 7) return;) incorrectly excludes users with exactly 7 idle days;
update the boundary to be inclusive of 7 days by changing the condition to check
for strictly less than 7 (i.e., use idleDays < 7) in the function handling the
"group-idle-7d+" logic so users with exactly 7 days are included; locate the
conditional that references idleDays in models/discordactions.js and replace the
comparison accordingly.
- Around line 687-695: The idle-7d scan is doing an extra Firestore read per
user by calling userStatusModel.doc(userStatus.id).get() inside the Promise.all;
remove that read and instead ensure the userStatus objects already include the
fields needed by computeIdleDaysExcludingOOO (idleWindowStartedAt, lastOooFrom,
lastOooUntil, and currentStatus.from). Update the producer that builds
userStatus (the getAllUserStatus function in models/userStatus.js) to populate
those fields on each userStatus so the code in models/discordactions.js can call
computeIdleDaysExcludingOOO using the existing userStatus object without any
further doc.get().

In `@models/userStatus.js`:
- Around line 256-258: When transitioning back to ACTIVE, clear any stale idle
anchor by resetting newStatusData.idleWindowStartedAt to null/undefined;
specifically, in the state-transition logic that checks requestedNextState and
previousState (the branch where requestedNextState === userState.ACTIVE and
previousState === userState.IDLE or similar), set
newStatusData.idleWindowStartedAt = null (or delete it) so the idle-day
calculation doesn't use a stale value; update the same control paths that set
idleWindowStartedAt (the branch using currentStatus?.from ??
currentStatus?.updatedAt) to ensure symmetry.

In `@test/unit/utils/userStatus.test.js`:
- Around line 114-139: The time-based tests calling computeIdleDaysExcludingOOO
use multiple Date.now() calls which can drift; fix each affected "it" block (the
tests "should return total idle days when no OOO period", "should exclude last
OOO period from idle days", and "should fall back to currentStatusFrom when
idleWindowStartedAt is missing") by capturing a single const now = Date.now() at
the top of the test and deriving windowStart, oooFrom, oooUntil, and
currentStatusFrom from that single now before calling
computeIdleDaysExcludingOOO so all timestamps are deterministic.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b705b0 and 4cc2b17.

📒 Files selected for processing (4)
  • models/discordactions.js
  • models/userStatus.js
  • test/unit/utils/userStatus.test.js
  • utils/userStatus.js

Comment thread models/discordactions.js Outdated
Comment thread models/discordactions.js Outdated
Comment thread models/userStatus.js Outdated
Comment thread test/unit/utils/userStatus.test.js Outdated
Comment thread models/userStatus.js
}
}
}
const lastOooUntilUpdate = resolveLastOooUntil({
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

previously we were storing lastOooUntilUpdate in userStatus, since we are removing that here can you please confirm that isn't being used anywhere?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

lastOooUntilUpdate isn't being used anywhere anymore
the fields lastOooFrom, lastOooUntil, and oooPeriods are effectively dead in terms of being updated in the usersStatus collection. The new getApprovedOooPeriods() handles everything dynamically via the requests collection now

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

mappedUser.lastOooUntil = userStatusData.lastOooUntil ?? null;

can you please check getMissedProgressUpdatesUsers in discordactions

Copy link
Copy Markdown
Member Author

@vinit717 vinit717 Mar 17, 2026

Choose a reason for hiding this comment

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

lastOooUntil is still stored in the userStatus collection and is used by getMissedProgressUpdatesUsers (around line 1180) to apply a grace period check.

Even though we stopped updating lastOooFrom/lastOooUntil during the refactor, the field was intentionally kept for backward compatibility. Existing users may still have valid lastOooUntil values, which the cron job relies on to grant grace periods.

In the future, this can be refactored to use the new requests collection (getApprovedOooPeriods()), but for now, everything remains safe and functional, and no behavior is broken

Since now we are just targeting the idle user, not the progress calculation, so I didn't update it here

Comment thread utils/userStatus.js Outdated
Comment thread utils/userStatus.js Outdated
Comment thread test/integration/taskBasedStatusUpdate.test.js
Comment thread models/userStatus.js
Comment thread models/userStatus.js Outdated
Comment thread models/discordactions.js Outdated
Comment thread models/discordactions.js Outdated
…on for accurate group idle 7d+ tracking, alongside new documentation.
…ns and update user status handling accordingly
…l` for improved OOO state transition handling
AnujChhikara
AnujChhikara previously approved these changes Mar 17, 2026
…in user status management and update related tests
Comment thread utils/userStatus.js
Comment on lines +87 to +100
const snapshot = await requestsModel
.where("requestedBy", "==", userId)
.where("type", "==", "OOO")
.where("until", ">=", windowStart)
.get();

const periods = [];
snapshot.forEach((doc) => {
const data = doc.data();
const isApproved = data.state === "APPROVED";
if (!isApproved) return;

const from = normalizeTimestamp(data.from);
const until = normalizeTimestamp(data.until);
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.

@vinit717 This can be part of the query itself, get the approved requests only

Copy link
Copy Markdown
Contributor

@prakashchoudhary07 prakashchoudhary07 left a comment

Choose a reason for hiding this comment

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

Approving it for now.
A follow-up PR will be raised by @vinit717 for improvements, idle time edge case fix, and also for the issue where users come back early from OOO, then the status for them

@prakashchoudhary07 prakashchoudhary07 merged commit 750beab into develop Mar 18, 2026
4 checks passed
@prakashchoudhary07 prakashchoudhary07 deleted the fix/idle-7day+ branch March 18, 2026 04:41
@vinit717 vinit717 mentioned this pull request Mar 18, 2026
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix the flow of idle user tagging

4 participants