Skip to content

Commit

Permalink
Update romcal and refactor output celebration
Browse files Browse the repository at this point in the history
  • Loading branch information
emagnier committed Feb 11, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent fa79948 commit b657385
Showing 11 changed files with 121 additions and 89 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@ module.exports = {
'ts': 'never',
'tsx': 'never'
}
]
],
'max-len': 120
}
};
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ Output an `Array` of locales keys, supported by romcal.

- Get celebrations `GET /calendar/{name}/{locale}/{date}`

Output an `Array` of celebrations ordered by date. For all endpoints:
Output an `Object` where the `celebrations` property contains an `Array` of celebrations ordered by date. For all endpoints:

- `{name}`: represent the name of the calendar, generally a country name. For example `italy`.
If the calendar doesn't exist, romcal will return a `404 NOT FOUND`.
@@ -193,7 +193,7 @@ You can, of course, combine different filters. For example `/calendar/spain/es?w

- `group=[string]`: Calendar dates can be grouped by various criteria upon invocation like so: `days`, `months`, `days-by-month`, `weeks-by-month`, `cycles`, `types`, `liturgical-seasons`, `liturgical-colors`, `psalter-weeks`.

When using this parameter, romcal-api output first an `Object` where keys represent the grouped data.
When using this parameter, the `celebrations` property will be an `Object` where keys represent the grouped data.
If the criteria aren't recognized, romcap-api will return an error (`422 UNPROCESSABLE ENTRY`).

### <a name="getVersion"></a> Get the API version
@@ -265,6 +265,7 @@ Note: this step as well as tests are run automatically before releasing a new ve

## History

- 1.1.0 Update romcal dependency. API change, the returned data is now an `Object` that contains the celebrations in a specific `celebrations` property. On each celebration, the `moment` property is renamed to `date`.
- 1.0.6 Calendar refactor and a lot of new tests added. Bug fixes.
- 1.0.5 Add new calendar tests and fix bugs. Fix the nodemon debug mode.
- 1.0.4 Add 404 error message on "Not found pages".
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "romcal-api",
"version": "1.0.6",
"version": "1.1.0",
"description": "REST API for liturgical calendars in Catholic Roman rite (Western Church). Powered by romcal.",
"main": "dist/src/index.js",
"engines": {
@@ -39,7 +39,7 @@
"express": "^4.17.1",
"lodash": "^4.17.15",
"moment": "^2.24.0",
"romcal": "^1.3.0",
"romcal": "^1.3.1-alpha.5",
"serverless-http": "^2.3.1"
},
"devDependencies": {
12 changes: 6 additions & 6 deletions src/routes/calendar/date-item-collection.spec.ts
Original file line number Diff line number Diff line change
@@ -9,8 +9,8 @@ describe( `GET /calendar`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
expect(Array.isArray(res.body)).toBeTruthy();
res.body.forEach((str) => expect(typeof str).toBe('object'));
expect(Array.isArray(res.body.celebrations)).toBeTruthy();
res.body.celebrations.forEach((str) => expect(typeof str).toBe('object'));
})
);

@@ -20,12 +20,12 @@ describe( `GET /calendar`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let expectedKeys = ['moment', 'type', 'name', 'data', 'key', 'source'].sort();
let expectedKeys = ['date', 'type', 'name', 'data', 'key'].sort();
let expectedDataKeys = ['season', 'meta', 'calendar'].sort();
let expectedMetaKeys = ['psalterWeek', 'liturgicalColor', 'cycle'].sort();
let expectedMetaKeys = ['psalterWeek', 'cycle'].sort();

res.body.forEach((item) => {
expect(Object.keys(item).sort()).toEqual(expectedKeys);
res.body.celebrations.forEach((item) => {
expect(Object.keys(item).sort()).toEqual(expect.arrayContaining(expectedKeys));
expect(Object.keys(item.data).sort()).toEqual(expect.arrayContaining(expectedDataKeys));
expect(Object.keys(item.data.meta).sort()).toEqual(expect.arrayContaining(expectedMetaKeys));
});
66 changes: 48 additions & 18 deletions src/routes/calendar/date-item-collection.ts
Original file line number Diff line number Diff line change
@@ -3,6 +3,12 @@ import * as romcal from 'romcal';
import moment from 'moment';
import periods from '../../constants/periods';
import Utils from './utils';
// import RomcalConfig from '../../../node_modules/romcal/dist/lib/Config.js';

type RomcalData = {
celebrations: Object[] | Object,
romcalConfig: Object
};

export default class DateItemCollection {
day: number;
@@ -123,6 +129,24 @@ export default class DateItemCollection {
};
}

private getDatesFromRomcal(): RomcalData {
const romcalConfig = {}; // new RomcalConfig(this.config);
const celebrations = romcal.calendarFor(this.config);

// Remove private and unnecessary properties
// Todo: these properties should be removed by romcal
/* eslint no-underscore-dangle: ["error", { "allow": ["_id", "_stack"] }] */
celebrations.map((celebration) => {
const c = celebration;
delete c._id;
delete c._stack;
delete c.moment;
return c;
});

return { celebrations, romcalConfig };
}

private getCurrentYear() {
this.config.year = new Date().getUTCFullYear();

@@ -133,19 +157,19 @@ export default class DateItemCollection {
this.config.year = Utils.getBeginningLiturgicalYear(new Date());
}

return this.getYear();
return this.getDatesFromRomcal();
}

private getYear() {
return romcal.calendarFor(_.clone(this.config));
return this.getDatesFromRomcal();
}

private getMonth() {
return this.getYear();
return this.getDatesFromRomcal();
}

private getDate() {
const dates = this.getYear();
const cal = this.getDatesFromRomcal();

// On liturgical calendar, the year is the moment where a liturgical calendar start.
// So if the provided date is before the first Sunday of Advent in the current civil year,
@@ -157,7 +181,7 @@ export default class DateItemCollection {
}

// Find the optional day from the results (romcal doesn't support lookup for a specific day)
return DateItemCollection.filterDateItemsByCriteria(dates, (item) => moment(item.moment).isSame(date, 'day'));
return DateItemCollection.filterDateItemsByCriteria(cal, (item) => moment(item.date).isSame(date, 'day'));
}

private getAlias(date) {
@@ -199,31 +223,31 @@ export default class DateItemCollection {
this.config.type = 'liturgical';
}

const dates = this.getYear();
const cal = this.getDatesFromRomcal();

// Todo: the Easter Triduum should be managed by romcal, and be excluded from the season of lent
const excludeFromLent = ['goodFriday', 'holySaturday', 'easter'];
const easterTriduum = ['holyThursday', ...excludeFromLent];

let christmas;
if (period === 'christmas-octave') {
christmas = _.find(dates, { key: 'christmas' });
christmas = _.find(cal.celebrations, { key: 'christmas' });
}

let easter;
if (period === 'easter-octave') {
easter = _.find(dates, { key: 'easter' });
easter = _.find(cal.celebrations, { key: 'easter' });
}

return DateItemCollection.filterDateItemsByCriteria(dates, (item) => {
return DateItemCollection.filterDateItemsByCriteria(cal, (item) => {
if (period === 'christmas-octave') {
return moment(item.moment).isSameOrAfter(christmas.moment)
&& moment(item.moment).isSameOrBefore(moment(christmas.moment).add(7, 'day'));
return moment(item.date).isSameOrAfter(christmas.date)
&& moment(item.date).isSameOrBefore(moment(christmas.date).add(7, 'day'));
}

if (period === 'easter-octave') {
return moment(item.moment).isSameOrAfter(easter.moment)
&& moment(item.moment).isSameOrBefore(moment(easter.moment).add(7, 'day'));
return moment(item.date).isSameOrAfter(easter.date)
&& moment(item.date).isSameOrBefore(moment(easter.date).add(7, 'day'));
}

if (period === 'lent' && excludeFromLent.indexOf(item.key) > -1) return false;
@@ -235,17 +259,23 @@ export default class DateItemCollection {

private getCelebrationLookup() {
const celebration = this.key;
const dates = this.getYear();
return DateItemCollection.filterDateItemsByCriteria(dates, (item) => item.key === celebration);
const cal = this.getDatesFromRomcal();
return DateItemCollection.filterDateItemsByCriteria(cal, (item) => item.key === celebration);
}

private static filterDateItemsByCriteria(dates: any, fn: Function): Object[] {
if (Array.isArray(dates)) return _.filter(dates, (item) => fn(item));
private static filterDateItemsByCriteria(cal: RomcalData, fn: Function): RomcalData {
const filteredCal = cal;

if (Array.isArray(cal.celebrations)) {
filteredCal.celebrations = _.filter(cal.celebrations, (item) => fn(item));
return filteredCal;
}

// For grouped data, we need to filter in each groups
// and only return groups that have items
return _(dates)
filteredCal.celebrations = _(cal.celebrations)
.map((group, key) => ({ [key]: _.filter(group, (item) => fn(item)) }))
.filter((group) => group[Object.keys(group)[0]].length);
return filteredCal;
}
}
18 changes: 9 additions & 9 deletions src/routes/calendar/day.spec.ts
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
expect(formatDate(date)).toBe('2025-02-03');
})
);
@@ -24,7 +24,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
expect(formatDate(date)).toBe('2025-11-30');
})
);
@@ -35,7 +35,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
expect(formatDate(date)).toBe('2026-11-28');
})
);
@@ -50,7 +50,7 @@ describe( `GET /calendar - Day`, () => {
// the API will try to find it the year after.
// But the liturgical year for 2025-2026 is finishing 2026-11-28.
// So in this liturgical year November 29 does't exist and romcal return an empty Array.
expect(res.body.length).toBe(0);
expect(res.body.celebrations.length).toBe(0);
})
);

@@ -60,7 +60,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
let today = new Date();
let year = today.getUTCFullYear();
let month = (today.getUTCMonth() + 1).toString().padStart(2, '0');
@@ -76,7 +76,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
let today = new Date();
let year = today.getUTCFullYear();
let month = (today.getUTCMonth() + 1).toString().padStart(2, '0');
@@ -92,7 +92,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
let today = new Date();
let year = today.getUTCFullYear();
let month = (today.getUTCMonth() + 1).toString().padStart(2, '0');
@@ -108,7 +108,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
let today = new Date();
let year = today.getUTCFullYear();
let month = (today.getUTCMonth() + 1).toString().padStart(2, '0');
@@ -124,7 +124,7 @@ describe( `GET /calendar - Day`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let date = moment(res.body[0].moment);
let date = moment(res.body.celebrations[0].date);
let today = new Date();
let year = today.getUTCFullYear();
let month = (today.getUTCMonth() + 1).toString().padStart(2, '0');
16 changes: 8 additions & 8 deletions src/routes/calendar/month.spec.ts
Original file line number Diff line number Diff line change
@@ -13,8 +13,8 @@ describe( `GET /calendar - Month`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let firstDate = moment(res.body[0].moment);
let lastDate = moment(res.body[res.body.length-1].moment);
let firstDate = moment(res.body.celebrations[0].date);
let lastDate = moment(res.body.celebrations[res.body.celebrations.length-1].date);

expect(formatDate(firstDate)).toBe('2025-12-01');
expect(formatDate(lastDate)).toBe('2025-12-31');
@@ -27,12 +27,12 @@ describe( `GET /calendar - Month`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let firstDate = res.body[0].moment;
let lastDate = res.body[res.body.length-1].moment;
let firstDate = res.body.celebrations[0].date;
let lastDate = res.body.celebrations[res.body.celebrations.length-1].date;

expect(formatDate(firstDate)).toBe('2026-04-01');
expect(formatDate(lastDate)).toBe('2026-04-30');
res.body.forEach(item => expect(moment(item.moment).month()).toBe(3));
res.body.celebrations.forEach(item => expect(moment(item.date).month()).toBe(3));
})
);

@@ -42,12 +42,12 @@ describe( `GET /calendar - Month`, () => {
.expect('Content-Type', /json/)
.expect(200)
.expect(function(res) {
let firstDate = moment(res.body[0].moment);
let lastDate = moment(res.body[res.body.length-1].moment);
let firstDate = moment(res.body.celebrations[0].date);
let lastDate = moment(res.body.celebrations[res.body.celebrations.length-1].date);

expect(formatDate(firstDate)).toBe('2025-11-30');
expect(formatDate(lastDate)).toBe('2026-11-28');
res.body.forEach(item => expect(moment(item.moment).month()).toBe(10));
res.body.celebrations.forEach(item => expect(moment(item.date).month()).toBe(10));
})
);

Loading
Oops, something went wrong.

0 comments on commit b657385

Please sign in to comment.