mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
make content releases use a given offset to the time.
This commit is contained in:
@@ -89,5 +89,6 @@
|
|||||||
"REDIS_PASSWORD": "12345678",
|
"REDIS_PASSWORD": "12345678",
|
||||||
"TRUSTED_DOMAINS": "localhost,https://habitica.com",
|
"TRUSTED_DOMAINS": "localhost,https://habitica.com",
|
||||||
"TIME_TRAVEL_ENABLED": "false",
|
"TIME_TRAVEL_ENABLED": "false",
|
||||||
"DEBUG_ENABLED": "false"
|
"DEBUG_ENABLED": "false",
|
||||||
|
"CONTENT_SWITCHOVER_TIME_OFFSET": 8
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,8 +116,8 @@
|
|||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"cross-spawn": "^7.0.3",
|
"cross-spawn": "^7.0.3",
|
||||||
"mocha": "^5.1.1",
|
"mocha": "^5.1.1",
|
||||||
"nyc": "^15.1.0",
|
|
||||||
"monk": "^7.3.4",
|
"monk": "^7.3.4",
|
||||||
|
"nyc": "^15.1.0",
|
||||||
"require-again": "^2.0.0",
|
"require-again": "^2.0.0",
|
||||||
"run-rs": "^0.7.7",
|
"run-rs": "^0.7.7",
|
||||||
"sinon-chai": "^3.7.0",
|
"sinon-chai": "^3.7.0",
|
||||||
|
|||||||
67
test/common/fns/datedMemoize.test.js
Normal file
67
test/common/fns/datedMemoize.test.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
/* eslint-disable global-require */
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
|
||||||
|
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
||||||
|
|
||||||
|
describe('datedMemoize', () => {
|
||||||
|
it('should return a function that returns a function', () => {
|
||||||
|
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
|
||||||
|
const memoized = datedMemoize(() => {});
|
||||||
|
expect(memoized).to.be.a('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not call multiple times', () => {
|
||||||
|
const stub = sandbox.stub().returns({});
|
||||||
|
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
|
||||||
|
const memoized = datedMemoize(stub);
|
||||||
|
memoized(1, 2);
|
||||||
|
memoized(1, 3);
|
||||||
|
expect(stub).to.have.been.calledOnce;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('call multiple times for different identifiers', () => {
|
||||||
|
const stub = sandbox.stub().returns({});
|
||||||
|
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
|
||||||
|
const memoized = datedMemoize(stub);
|
||||||
|
memoized({ identifier: 'a', memoizeConfig: true }, 1, 2);
|
||||||
|
memoized({ identifier: 'b', memoizeConfig: true }), 1, 2;
|
||||||
|
expect(stub).to.have.been.calledTwice;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('call once for the same identifier', () => {
|
||||||
|
const stub = sandbox.stub().returns({});
|
||||||
|
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
|
||||||
|
const memoized = datedMemoize(stub);
|
||||||
|
memoized({ identifier: 'a', memoizeConfig: true }, 1, 2);
|
||||||
|
memoized({ identifier: 'a', memoizeConfig: true }, 1, 2);
|
||||||
|
expect(stub).to.have.been.calledOnce;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('call once on the same day', () => {
|
||||||
|
const stub = sandbox.stub().returns({});
|
||||||
|
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
|
||||||
|
const memoized = datedMemoize(stub);
|
||||||
|
memoized({ date: new Date('2024-01-01'), memoizeConfig: true }, 1, 2);
|
||||||
|
memoized({ date: new Date('2024-01-01'), memoizeConfig: true }, 1, 2);
|
||||||
|
expect(stub).to.have.been.calledOnce;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('call multiple times on different days', () => {
|
||||||
|
const stub = sandbox.stub().returns({});
|
||||||
|
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
|
||||||
|
const memoized = datedMemoize(stub);
|
||||||
|
memoized({ date: new Date('2024-01-01'), memoizeConfig: true }, 1, 2);
|
||||||
|
memoized({ date: new Date('2024-01-02'), memoizeConfig: true }, 1, 2);
|
||||||
|
expect(stub).to.have.been.calledTwice;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects switchover time', () => {
|
||||||
|
const stub = sandbox.stub().returns({});
|
||||||
|
const datedMemoize = require('../../../website/common/script/fns/datedMemoize').default;
|
||||||
|
const memoized = datedMemoize(stub);
|
||||||
|
memoized({ date: new Date('2024-01-01T00:00:00.000Z'), memoizeConfig: true }, 1, 2);
|
||||||
|
memoized({ date: new Date(`2024-01-01T${String(SWITCHOVER_TIME).padStart(2, '0')}`), memoizeConfig: true }, 1, 2);
|
||||||
|
expect(stub).to.have.been.calledTwice;
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -26,7 +26,7 @@ describe('armoire', () => {
|
|||||||
clock.restore();
|
clock.restore();
|
||||||
});
|
});
|
||||||
it('does not return unreleased gear', async () => {
|
it('does not return unreleased gear', async () => {
|
||||||
clock = sinon.useFakeTimers(new Date('2024-01-01'));
|
clock = sinon.useFakeTimers(new Date('2024-01-02'));
|
||||||
const items = makeArmoireIitemList();
|
const items = makeArmoireIitemList();
|
||||||
expect(items.length).to.equal(377);
|
expect(items.length).to.equal(377);
|
||||||
expect(items.filter(item => item.set === 'pottersSet' || item.set === 'optimistSet' || item.set === 'schoolUniform')).to.be.an('array').that.is.empty;
|
expect(items.filter(item => item.set === 'pottersSet' || item.set === 'optimistSet' || item.set === 'schoolUniform')).to.be.an('array').that.is.empty;
|
||||||
@@ -47,7 +47,7 @@ describe('armoire', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('releases gear when appropriate', async () => {
|
it('releases gear when appropriate', async () => {
|
||||||
clock = sinon.useFakeTimers(new Date('2024-01-01'));
|
clock = sinon.useFakeTimers(new Date('2024-01-01T00:00:00.000Z'));
|
||||||
const items = makeArmoireIitemList();
|
const items = makeArmoireIitemList();
|
||||||
expect(items.length).to.equal(377);
|
expect(items.length).to.equal(377);
|
||||||
clock.restore();
|
clock.restore();
|
||||||
@@ -57,8 +57,13 @@ describe('armoire', () => {
|
|||||||
expect(januaryItems.length).to.equal(381);
|
expect(januaryItems.length).to.equal(381);
|
||||||
clock.restore();
|
clock.restore();
|
||||||
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
|
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
|
||||||
clock = sinon.useFakeTimers(new Date('2024-02-20'));
|
clock = sinon.useFakeTimers(new Date('2024-02-07'));
|
||||||
|
const januaryItems2 = makeArmoireIitemList();
|
||||||
|
expect(januaryItems2.length).to.equal(381);
|
||||||
|
clock.restore();
|
||||||
|
delete require.cache[require.resolve('../../website/common/script/content/gear/sets/armoire')];
|
||||||
|
clock = sinon.useFakeTimers(new Date('2024-02-07T09:00:00.000Z'));
|
||||||
const febuaryItems = makeArmoireIitemList();
|
const febuaryItems = makeArmoireIitemList();
|
||||||
expect(febuaryItems.length).to.equal(384);
|
expect(febuaryItems.length).to.equal(381);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import nconf from 'nconf';
|
||||||
import {
|
import {
|
||||||
getAllScheduleMatchingGroups, clearCachedMatchers, MONTHLY_SCHEDULE, GALA_SCHEDULE,
|
getAllScheduleMatchingGroups, clearCachedMatchers, MONTHLY_SCHEDULE, GALA_SCHEDULE,
|
||||||
} from '../../website/common/script/content/constants/schedule';
|
} from '../../website/common/script/content/constants/schedule';
|
||||||
@@ -16,7 +17,10 @@ function validateMatcher (matcher, checkedDate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe('Content Schedule', () => {
|
describe('Content Schedule', () => {
|
||||||
|
let switchoverTime;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
switchoverTime = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
||||||
clearCachedMatchers();
|
clearCachedMatchers();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,8 +54,8 @@ describe('Content Schedule', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('assembles scheduled items on march 21st', () => {
|
it('assembles scheduled items on march 22st', () => {
|
||||||
const date = new Date('2024-03-21');
|
const date = new Date('2024-03-22');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
for (const key in matchers) {
|
for (const key in matchers) {
|
||||||
if (matchers[key]) {
|
if (matchers[key]) {
|
||||||
@@ -92,31 +96,31 @@ describe('Content Schedule', () => {
|
|||||||
it('sets the end date if its in the same month', () => {
|
it('sets the end date if its in the same month', () => {
|
||||||
const date = new Date('2024-04-03');
|
const date = new Date('2024-04-03');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-04-07').toDate());
|
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-04-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets the end date if its in the next day', () => {
|
it('sets the end date if its in the next day', () => {
|
||||||
const date = new Date('2024-05-06T14:00:00.000Z');
|
const date = new Date('2024-05-06T14:00:00.000Z');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-05-07').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', () => {
|
||||||
const date = new Date('2024-05-07');
|
const date = new Date('2024-05-07T07:00:00.000Z');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-06-07').toDate());
|
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-06-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets the end date if its next month', () => {
|
it('sets the end date if its next month', () => {
|
||||||
const date = new Date('2024-05-20T01:00:00.000Z');
|
const date = new Date('2024-05-20T01:00:00.000Z');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
expect(matchers.backgrounds.end).to.eql(moment.utc('2024-06-07').toDate());
|
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-06-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('sets the end date for a gala', () => {
|
it('sets the end date for a gala', () => {
|
||||||
const date = new Date('2024-05-20');
|
const date = new Date('2024-05-20');
|
||||||
const matchers = getAllScheduleMatchingGroups(date);
|
const matchers = getAllScheduleMatchingGroups(date);
|
||||||
expect(matchers.seasonalGear.end).to.eql(moment.utc('2024-06-21').toDate());
|
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2024-06-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||||
});
|
});
|
||||||
|
|
||||||
it('contains content for repeating events', () => {
|
it('contains content for repeating events', () => {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import nconf from 'nconf';
|
||||||
import SEASONAL_SETS from './seasonalSets';
|
import SEASONAL_SETS from './seasonalSets';
|
||||||
import { getRepeatingEvents } from './events';
|
import { getRepeatingEvents } from './events';
|
||||||
|
|
||||||
@@ -773,6 +774,8 @@ export const GALA_SCHEDULE = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
||||||
|
|
||||||
export const TYPE_SCHEDULE = {
|
export const TYPE_SCHEDULE = {
|
||||||
timeTravelers: FIRST_RELEASE_DAY,
|
timeTravelers: FIRST_RELEASE_DAY,
|
||||||
backgrounds: SECOND_RELEASE_DAY,
|
backgrounds: SECOND_RELEASE_DAY,
|
||||||
@@ -790,7 +793,9 @@ function getDay (date) {
|
|||||||
if (date === undefined) {
|
if (date === undefined) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return date instanceof moment ? date.date() : date.getDate();
|
const checkDate = new Date(date.getTime());
|
||||||
|
checkDate.setHours(checkDate.getHours() - SWITCHOVER_TIME);
|
||||||
|
return checkDate.getDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMonth (date) {
|
function getMonth (date) {
|
||||||
@@ -871,7 +876,7 @@ function makeMatcherClass (date) {
|
|||||||
function makeEndDate (checkedDate, matcher) {
|
function makeEndDate (checkedDate, matcher) {
|
||||||
let end = moment.utc(checkedDate);
|
let end = moment.utc(checkedDate);
|
||||||
end.date(TYPE_SCHEDULE[matcher.type]);
|
end.date(TYPE_SCHEDULE[matcher.type]);
|
||||||
end.hour(0);
|
end.hour(SWITCHOVER_TIME);
|
||||||
end.minute(0);
|
end.minute(0);
|
||||||
end.second(0);
|
end.second(0);
|
||||||
if (matcher.endMonth !== undefined) {
|
if (matcher.endMonth !== undefined) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import defaults from 'lodash/defaults';
|
|||||||
import find from 'lodash/find';
|
import find from 'lodash/find';
|
||||||
import forEach from 'lodash/forEach';
|
import forEach from 'lodash/forEach';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import nconf from 'nconf';
|
||||||
import upperFirst from 'lodash/upperFirst';
|
import upperFirst from 'lodash/upperFirst';
|
||||||
import { ownsItem } from '../gear-helper';
|
import { ownsItem } from '../gear-helper';
|
||||||
import { ATTRIBUTES } from '../../../constants';
|
import { ATTRIBUTES } from '../../../constants';
|
||||||
@@ -1832,6 +1833,7 @@ const weapon = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
||||||
const releaseDay = 7;
|
const releaseDay = 7;
|
||||||
const releaseDates = {
|
const releaseDates = {
|
||||||
somethingSpooky: { year: 2023, month: 10 },
|
somethingSpooky: { year: 2023, month: 10 },
|
||||||
@@ -1888,7 +1890,7 @@ forEach({
|
|||||||
|
|
||||||
function updateReleased (type) {
|
function updateReleased (type) {
|
||||||
const today = moment();
|
const today = moment();
|
||||||
const releaseDateEndPart = `${String(releaseDay).padStart(2, '0')}T08:00-0500`;
|
const releaseDateEndPart = `${String(releaseDay).padStart(2, '0')}T${String(SWITCHOVER_TIME).padStart(2, '0')}:00-0500`;
|
||||||
const returnType = {};
|
const returnType = {};
|
||||||
forEach(type, (gearItem, gearKey) => {
|
forEach(type, (gearItem, gearKey) => {
|
||||||
let released;
|
let released;
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
|
||||||
|
const SWITCHOVER_TIME = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
||||||
|
|
||||||
function getDay (date) {
|
function getDay (date) {
|
||||||
if (date === undefined) {
|
if (date === undefined) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return date instanceof moment ? date.date() : date.getDate();
|
const checkDate = new Date(date.getTime());
|
||||||
|
checkDate.setHours(checkDate.getHours() - SWITCHOVER_TIME);
|
||||||
|
return checkDate.getDate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMonth (date) {
|
function getMonth (date) {
|
||||||
|
|||||||
Reference in New Issue
Block a user