mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 06:37:23 +01:00
Fix schedule using wrong month at the beginning hours of month (#15290)
* Fix schedule using wrong month at the beginning hours of month * fix broken test * fix switchover for time based matchers * Fix scheduling issue related to timezones * Fix end date creating issues
This commit is contained in:
@@ -47,9 +47,9 @@ describe('shops', () => {
|
|||||||
|
|
||||||
describe('premium hatching potions', () => {
|
describe('premium hatching potions', () => {
|
||||||
it('contains current scheduled premium hatching potions', async () => {
|
it('contains current scheduled premium hatching potions', async () => {
|
||||||
clock = sinon.useFakeTimers(new Date('2024-04-01'));
|
clock = sinon.useFakeTimers(new Date('2024-04-01T09:00:00.000Z'));
|
||||||
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
||||||
expect(potions.items.length).to.eql(2);
|
expect(potions.items.length).to.eql(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not contain past scheduled premium hatching potions', async () => {
|
it('does not contain past scheduled premium hatching potions', async () => {
|
||||||
@@ -73,9 +73,9 @@ describe('shops', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not contain locked quest premium hatching potions', async () => {
|
it('does not contain locked quest premium hatching potions', async () => {
|
||||||
clock = sinon.useFakeTimers(new Date('2024-04-01'));
|
clock = sinon.useFakeTimers(new Date('2024-04-01T09:00:00.000Z'));
|
||||||
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
||||||
expect(potions.items.length).to.eql(2);
|
expect(potions.items.length).to.eql(3);
|
||||||
expect(potions.items.filter(x => x.key === 'Bronze' || x.key === 'BlackPearl').length).to.eql(0);
|
expect(potions.items.filter(x => x.key === 'Bronze' || x.key === 'BlackPearl').length).to.eql(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,19 @@ function validateMatcher (matcher, checkedDate) {
|
|||||||
|
|
||||||
describe('Content Schedule', () => {
|
describe('Content Schedule', () => {
|
||||||
let switchoverTime;
|
let switchoverTime;
|
||||||
|
let clock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
switchoverTime = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
switchoverTime = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
||||||
clearCachedMatchers();
|
clearCachedMatchers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
if (clock) {
|
||||||
|
clock.restore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('assembles scheduled items on january 15th', () => {
|
it('assembles scheduled items on january 15th', () => {
|
||||||
const date = new Date('2024-01-15');
|
const date = new Date('2024-01-15');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
@@ -105,8 +112,14 @@ describe('Content Schedule', () => {
|
|||||||
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-05-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-05-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets the end date if its on the release day', () => {
|
it('sets the end date if its on the release day before switchover', () => {
|
||||||
const date = new Date('2024-05-07T07:00:00.000Z');
|
const date = new Date('2024-05-07T07:00:00.000+00:00');
|
||||||
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
|
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-05-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets the end date if its on the release day after switchover', () => {
|
||||||
|
const date = new Date('2024-05-07T09:00:00.000+00:00');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-06-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-06-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
});
|
});
|
||||||
@@ -129,6 +142,42 @@ describe('Content Schedule', () => {
|
|||||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('uses correct date for first hours of the month', () => {
|
||||||
|
// if the date is checked before CONTENT_SWITCHOVER_TIME_OFFSET,
|
||||||
|
// it should be considered the previous month
|
||||||
|
const date = new Date('2024-05-01T02:00:00.000Z');
|
||||||
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
|
expect(matchers.petQuests.items).to.contain('snake');
|
||||||
|
expect(matchers.petQuests.items).to.not.contain('horse');
|
||||||
|
expect(matchers.timeTravelers.match('202304'), '202304').to.be.true;
|
||||||
|
expect(matchers.timeTravelers.match('202404'), '202404').to.be.false;
|
||||||
|
expect(matchers.timeTravelers.match('202305'), '202305').to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses correct date after switchover time', () => {
|
||||||
|
// if the date is checked after CONTENT_SWITCHOVER_TIME_OFFSET,
|
||||||
|
// it should be considered the current
|
||||||
|
const date = new Date('2024-05-01T09:00:00.000Z');
|
||||||
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
|
expect(matchers.petQuests.items).to.contain('snake');
|
||||||
|
expect(matchers.petQuests.items).to.not.contain('horse');
|
||||||
|
expect(matchers.timeTravelers.match('202304'), '202304').to.be.false;
|
||||||
|
expect(matchers.timeTravelers.match('202305'), '202305').to.be.true;
|
||||||
|
expect(matchers.timeTravelers.match('202405'), '202405').to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses UTC timezone', () => {
|
||||||
|
// if the date is checked after CONTENT_SWITCHOVER_TIME_OFFSET,
|
||||||
|
// it should be considered the current
|
||||||
|
clock = sinon.useFakeTimers(new Date('2024-05-01T05:00:00.000-04:00'));
|
||||||
|
const matchers = getAllScheduleMatchingGroups();
|
||||||
|
expect(matchers.petQuests.items).to.contain('snake');
|
||||||
|
expect(matchers.petQuests.items).to.not.contain('horse');
|
||||||
|
expect(matchers.timeTravelers.match('202304'), '202304').to.be.false;
|
||||||
|
expect(matchers.timeTravelers.match('202305'), '202305').to.be.true;
|
||||||
|
expect(matchers.timeTravelers.match('202405'), '202405').to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
it('contains content for repeating events', () => {
|
it('contains content for repeating events', () => {
|
||||||
const date = new Date('2024-04-15');
|
const date = new Date('2024-04-15');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ describe('time-travelers store', () => {
|
|||||||
|
|
||||||
describe('on may 1st', () => {
|
describe('on may 1st', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
date = new Date('2024-05-01');
|
date = new Date('2024-05-01T09:00:00.000Z');
|
||||||
});
|
});
|
||||||
it('returns the correct gear', () => {
|
it('returns the correct gear', () => {
|
||||||
const items = timeTravelers.timeTravelerStore(user, date);
|
const items = timeTravelers.timeTravelerStore(user, date);
|
||||||
|
|||||||
@@ -809,7 +809,9 @@ function getMonth (date) {
|
|||||||
if (date === undefined) {
|
if (date === undefined) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return date instanceof moment ? date.month() : date.getMonth();
|
const checkDate = new Date(date.getTime());
|
||||||
|
checkDate.setHours(checkDate.getHours() - SWITCHOVER_TIME);
|
||||||
|
return checkDate.getMonth();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGalaIndex (date) {
|
function getGalaIndex (date) {
|
||||||
@@ -892,7 +894,7 @@ function makeEndDate (checkedDate, matcher) {
|
|||||||
end.year(checkedDate.getFullYear() + 1);
|
end.year(checkedDate.getFullYear() + 1);
|
||||||
}
|
}
|
||||||
end.month(matcher.endMonth);
|
end.month(matcher.endMonth);
|
||||||
} else if (end.date() <= checkedDate.getDate()) {
|
} else if (end.valueOf() <= checkedDate.getTime()) {
|
||||||
end = moment(end).add(1, 'months');
|
end = moment(end).add(1, 'months');
|
||||||
}
|
}
|
||||||
return end.toDate();
|
return end.toDate();
|
||||||
@@ -904,7 +906,7 @@ export function clearCachedMatchers () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getAllScheduleMatchingGroups (date) {
|
export function getAllScheduleMatchingGroups (date) {
|
||||||
const checkedDate = date || new Date();
|
const checkedDate = date || moment.utc().toDate();
|
||||||
if (cacheDate !== null && (getDay(checkedDate) !== getDay(cacheDate)
|
if (cacheDate !== null && (getDay(checkedDate) !== getDay(cacheDate)
|
||||||
|| getMonth(checkedDate) !== getMonth(cacheDate))) {
|
|| getMonth(checkedDate) !== getMonth(cacheDate))) {
|
||||||
// Clear cached matchers, since they are old
|
// Clear cached matchers, since they are old
|
||||||
@@ -914,9 +916,14 @@ export function getAllScheduleMatchingGroups (date) {
|
|||||||
// No matchers exist, make new ones
|
// No matchers exist, make new ones
|
||||||
cacheDate = new Date();
|
cacheDate = new Date();
|
||||||
cachedScheduleMatchers = {};
|
cachedScheduleMatchers = {};
|
||||||
|
// subtract switchover time for the matcher classes, but
|
||||||
|
// NOT to decide which matchers to assemble.
|
||||||
|
// assembly uses getDate and getMonth which already adjust for switchover time
|
||||||
|
const adjustedDate = new Date(checkedDate.getTime());
|
||||||
|
adjustedDate.setHours(adjustedDate.getHours() - SWITCHOVER_TIME);
|
||||||
assembleScheduledMatchers(checkedDate).forEach(matcher => {
|
assembleScheduledMatchers(checkedDate).forEach(matcher => {
|
||||||
if (!cachedScheduleMatchers[matcher.type]) {
|
if (!cachedScheduleMatchers[matcher.type]) {
|
||||||
cachedScheduleMatchers[matcher.type] = makeMatcherClass(checkedDate);
|
cachedScheduleMatchers[matcher.type] = makeMatcherClass(adjustedDate);
|
||||||
}
|
}
|
||||||
cachedScheduleMatchers[matcher.type].end = makeEndDate(checkedDate, matcher);
|
cachedScheduleMatchers[matcher.type].end = makeEndDate(checkedDate, matcher);
|
||||||
if (matcher.matcher instanceof Function) {
|
if (matcher.matcher instanceof Function) {
|
||||||
|
|||||||
Reference in New Issue
Block a user