Date override fixes - #1
Conversation
There was a problem hiding this comment.
审查摘要
- packages/lib/slots.ts: 发现重复调用 dayjs() 两次,造成性能冗余,已委托深审并确认。
- packages/trpc/server/routers/viewer/slots.ts: 发现时区校验缺失、工作时间检查逻辑错误(start/end 时间相同),影响可用性判断,已委托深审并确认。
- 其余文件:batch 审计通过,无高危问题。
由 CodeHawk 提供支持 · nuwa
| } | ||
| ); | ||
|
|
||
| const scheduleForEventOnADayWithDateOverrideDifferentTimezone = await getSchedule( |
There was a problem hiding this comment.
🟡 AI 代码审查发现问题
📋 问题概述
测试用例中新增了对不同时区(+6:00)的 getSchedule 调用,但注释说明‘it should return the same as this is the utc time’存在误导性。实际逻辑中,getSchedule 的行为可能受时区影响,若未正确处理 UTC 时间转换,可能导致返回结果不一致。该注释暗示行为应相同,但未验证函数是否真正忽略时区差异,存在潜在逻辑错误风险。
📍 问题详情
🟡 问题 1 | 严重程度: MEDIUM | 行号: 788
💬 详细说明:
- 测试用例中新增了对不同时区(+6:00)的 getSchedule 调用,但注释说明‘it should return the same as this is the utc time’存在误导性。实际逻辑中,getSchedule 的行为可能受时区影响,若未正确处理 UTC 时间转换,可能导致返回结果不一致。该注释暗示行为应相同,但未验证函数是否真正忽略时区差异,存在潜在逻辑错误风险。
📝 问题代码:
const scheduleForEventOnADayWithDateOverrideDifferentTimezone = await getSchedule(
💡 修复建议:
移除误导性注释,或在代码中明确确保 getSchedule 在输入为 UTC 时间且 timeZone 不同时仍能正确处理时间边界。建议添加断言验证时区转换后的结果一致性,或重构逻辑以保证跨时区调用行为一致。
✅ 修复示例:
🔗 参考链接
无
| dayjs(override.start).utc().add(offset, "minute").hour() * 60 + | ||
| dayjs(override.start).utc().add(offset, "minute").minute(), | ||
| endTime: | ||
| dayjs(override.end).utc().add(offset, "minute").hour() * 60 + |
There was a problem hiding this comment.
🔴 AI 代码审查发现问题
📋 问题概述
发现 2 个邻近问题(第 219–222 行)
📍 问题详情
🔴 问题 1 | 严重程度: HIGH | 行号: 219
💬 详细说明:
- 每次处理覆盖时间时都会重复执行相同的日期转换操作,增加不必要的计算开销,特别是在大量覆盖数据情况下会影响性能;若 offset 超出合理范围,可能引发时间计算异常,导致系统行为不可控。
📝 问题代码:
dayjs(override.start).utc().add(offset, "minute").hour() * 60 + dayjs(override.start).utc().add(offset, "minute").minute()
💡 修复建议:
提取公共表达式,避免重复计算;同时添加对 offset 的有效性校验,确保其在合理范围内(例如 ±1440 分钟)。建议缓存 dayjs(override.start).utc().add(offset, "minute") 的结果,然后分别获取小时和分钟。
✅ 修复示例:
const adjustedStart = dayjs(override.start).utc().add(offset, "minute");
return {
userIds: override.userId ? [override.userId] : [],
startTime: adjustedStart.hour() * 60 + adjustedStart.minute(),
endTime: dayjs(override.end).utc().add(offset, "minute").hour() * 60 + dayjs(override.end).utc().add(offset, "minute").minute(),
};
🔴 问题 2 | 严重程度: HIGH | 行号: 222
💬 详细说明:
- 每次处理覆盖时间时都会重复执行相同的日期转换操作,增加不必要的计算开销,特别是在大量覆盖数据情况下会影响性能;同时存在因 offset 超出合理范围导致时间计算错误的风险。
📝 问题代码:
dayjs(override.end).utc().add(offset, "minute").hour() * 60 + dayjs(override.end).utc().add(offset, "minute").minute()
💡 修复建议:
提取公共表达式,避免重复计算;同时添加对 offset 的有效性校验,确保其在合理范围内(例如 ±1440 分钟)。
✅ 修复示例:
const adjustedEnd = dayjs(override.end).utc().add(offset, "minute");
return {
userIds: override.userId ? [override.userId] : [],
startTime: adjustedStart.hour() * 60 + adjustedStart.minute(),
endTime: adjustedEnd.hour() * 60 + adjustedEnd.minute(),
};
🔗 参考链接
无
| busy, | ||
| eventLength, | ||
| dateOverrides = [], | ||
| workingHours = [], |
There was a problem hiding this comment.
🟡 AI 代码审查发现问题
📋 问题概述
发现 2 个邻近问题(第 79–80 行)
📍 问题详情
🟡 问题 1 | 严重程度: MEDIUM | 行号: 79
💬 详细说明:
- 函数 checkIfIsAvailable 的参数 dateOverrides 被默认初始化为空数组,但其类型定义为可选(?),且在调用方传入时未明确处理空值。这可能导致后续逻辑误判:当实际无日期覆盖时,仍会进入 dateOverrides.find 判断分支,造成不必要的计算和潜在逻辑错误。
📝 问题代码:
dateOverrides = []
💡 修复建议:
将 dateOverrides 的默认值改为 null,并在函数内部显式判断是否为 null 或空数组,避免对空数组的无效遍历。同时更新函数签名以反映该参数可能为 null。
✅ 修复示例:
dateOverrides = null
🟡 问题 2 | 严重程度: MEDIUM | 行号: 80
💬 详细说明:
- workingHours 参数被默认初始化为空数组,但其类型为 WorkingHours[],且在函数中用于判断工作时间范围。若用户未设置任何工作时间,空数组会导致后续 find 检查始终返回 false,从而错误地认为所有时间段都处于非工作时间,导致可用性判断失效。
📝 问题代码:
workingHours = []
💡 修复建议:
将 workingHours 默认值设为 null,并在函数内增加对 null/undefined 的检查,确保不因空数组而误判。同时更新函数签名以体现该参数可为 null。
✅ 修复示例:
workingHours = null
🔗 参考链接
无
| workingHours.find((workingHour) => { | ||
| if (workingHour.days.includes(slotStartTime.day())) { | ||
| const start = slotStartTime.hour() * 60 + slotStartTime.minute(); | ||
| const end = slotStartTime.hour() * 60 + slotStartTime.minute(); |
There was a problem hiding this comment.
🟡 AI 代码审查发现问题
📋 问题概述
在 workingHours 检查逻辑中,start 和 end 变量被设置为相同的值(都基于 slotStartTime),这会导致工作时间检查逻辑错误
📍 问题详情
🟡 问题 1 | 严重程度: MEDIUM | 行号: 142
💬 详细说明:
- 工作时间检查逻辑错误,可能导致错误的时间槽可用性判断,影响日程安排功能的准确性
📝 问题代码:
const start = slotStartTime.hour() * 60 + slotStartTime.minute();
const end = slotStartTime.hour() * 60 + slotStartTime.minute();
💡 修复建议:
正确设置 start 和 end 时间,start 应基于 slotStartTime,end 应基于 slotEndTime
✅ 修复示例:
const start = slotStartTime.hour() * 60 + slotStartTime.minute();
const end = slotEndTime.hour() * 60 + slotEndTime.minute();
🔗 参考链接
无
| frequency: eventType.slotInterval || input.duration || eventType.length, | ||
| organizerTimeZone: | ||
| eventType.timeZone || eventType?.schedule?.timeZone || userAvailability?.[0]?.timeZone, | ||
| organizerTimeZone, |
There was a problem hiding this comment.
🔴 AI 代码审查发现问题
📋 问题概述
在 getTimeSlots 调用中传递 organizerTimeZone,但该参数未经过校验或默认值处理。若输入的 timeZone 为非法值(如 'invalid/timezone'),可能导致 dayjs.tz() 内部异常或返回错误时间,进而影响整个日程生成逻辑,存在潜在崩溃风险。
📍 问题详情
🔴 问题 1 | 严重程度: HIGH | 行号: 456
💬 详细说明:
- 在 getTimeSlots 调用中传递 organizerTimeZone,但该参数未经过校验或默认值处理。若输入的 timeZone 为非法值(如 'invalid/timezone'),可能导致 dayjs.tz() 内部异常或返回错误时间,进而影响整个日程生成逻辑,存在潜在崩溃风险。
📝 问题代码:
organizerTimeZone
💡 修复建议:
在调用 getTimeSlots 前,对 organizerTimeZone 进行有效性验证,若无效则使用默认值(如 'UTC')或抛出错误,防止不可控的时间解析行为。
✅ 修复示例:
organizerTimeZone: organizerTimeZone && dayjs.tz.isValid(organizerTimeZone) ? organizerTimeZone : 'UTC'
🔗 参考链接
无
| time: slot.time, | ||
| ...schedule, | ||
| ...availabilityCheckProps, | ||
| organizerTimeZone: schedule.timeZone, |
There was a problem hiding this comment.
🟡 AI 代码审查发现问题
📋 问题概述
在 checkIfIsAvailable 中,organizerTimeZone 被重复从 schedule.timeZone 传入,但该值已在上层调用中通过 organizerTimeZone 参数统一传递。此重复赋值冗余且易引发维护歧义,若未来修改调度逻辑,可能造成不一致。
📍 问题详情
🟡 问题 1 | 严重程度: MEDIUM | 行号: 492
💬 详细说明:
- 在 checkIfIsAvailable 中,organizerTimeZone 被重复从 schedule.timeZone 传入,但该值已在上层调用中通过 organizerTimeZone 参数统一传递。此重复赋值冗余且易引发维护歧义,若未来修改调度逻辑,可能造成不一致。
📝 问题代码:
organizerTimeZone: schedule.timeZone
💡 修复建议:
移除该行中的 organizerTimeZone 重传,直接使用外部传入的 organizerTimeZone 参数,保持上下文一致性。
✅ 修复示例:
organizerTimeZone
🔗 参考链接
无
| time: slot.time, | ||
| ...userSchedule, | ||
| ...availabilityCheckProps, | ||
| organizerTimeZone: userSchedule.timeZone, |
There was a problem hiding this comment.
🟡 AI 代码审查发现问题
📋 问题概述
在 looseHostAvailability 处理逻辑中,organizerTimeZone 从 userSchedule.timeZone 重新传入,但该值与外部传入的 organizerTimeZone 语义相同。重复赋值造成代码冗余,且若两者不一致,将破坏时间一致性,引入潜在 bug。
📍 问题详情
🟡 问题 1 | 严重程度: MEDIUM | 行号: 517
💬 详细说明:
- 在 looseHostAvailability 处理逻辑中,organizerTimeZone 从 userSchedule.timeZone 重新传入,但该值与外部传入的 organizerTimeZone 语义相同。重复赋值造成代码冗余,且若两者不一致,将破坏时间一致性,引入潜在 bug。
📝 问题代码:
organizerTimeZone: userSchedule.timeZone
💡 修复建议:
统一使用外部传入的 organizerTimeZone,移除此处的重复赋值,确保时间上下文一致。
✅ 修复示例:
organizerTimeZone
🔗 参考链接
无
| time: slot.time, | ||
| busy, | ||
| ...availabilityCheckProps, | ||
| organizerTimeZone: userSchedule?.timeZone, |
There was a problem hiding this comment.
🟡 AI 代码审查发现问题
📋 问题概述
在 selectedSlots 处理逻辑中,organizerTimeZone 从 userSchedule.timeZone 传入,但该值应与全局 organizerTimeZone 保持一致。若 userSchedule.timeZone 为空或不一致,将导致时间偏移错误,影响可用性判断。
📍 问题详情
🟡 问题 1 | 严重程度: MEDIUM | 行号: 585
💬 详细说明:
- 在 selectedSlots 处理逻辑中,organizerTimeZone 从 userSchedule.timeZone 传入,但该值应与全局 organizerTimeZone 保持一致。若 userSchedule.timeZone 为空或不一致,将导致时间偏移错误,影响可用性判断。
📝 问题代码:
organizerTimeZone: userSchedule?.timeZone
💡 修复建议:
统一使用外部传入的 organizerTimeZone,避免局部变量干扰,确保时间逻辑一致性。
✅ 修复示例:
organizerTimeZone
🔗 参考链接
无
What does this PR do?
This PR fixes that date overrides of fixed hosts are taken into account for round-robin events. This prevents round-robin events being booked where the fixed hosts are unavailable.
This PR also fixes that date overrides didn't adjust to different timezones. If the organizer has a date override from 10-11 UTC it always showed the slots from 10-11 open no matter what timezone the attendee has.
Fixes #8207
Fixes #8329
Fixes: #8273
Environment: Staging(main branch) / Production
Type of change
How should this be tested?
Date overrides for fixed hosts (round-robin):
Date override timezones issue: