diff --git a/package-lock.json b/package-lock.json index 18fba43..05ee76d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "graphql": "^15.5.0", "graphql-request": "^3.4.0", - "luxon": "^1.26.0" + "luxon": "^1.26.0", + "object-hash": "^2.1.1" }, "devDependencies": { "ava": "^3.15.0", @@ -6670,6 +6671,14 @@ "node": ">=0.10.0" } }, + "node_modules/object-hash": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.1.1.tgz", + "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==", + "engines": { + "node": ">= 6" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -16445,6 +16454,11 @@ } } }, + "object-hash": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.1.1.tgz", + "integrity": "sha512-VOJmgmS+7wvXf8CjbQmimtCnEx3IAoLxI3fp2fbWehxrWBcAQFbk+vcwb6vzR0VZv/eNCJ/27j151ZTwqW/JeQ==" + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", diff --git a/package.json b/package.json index 8ae4e6c..aa5a3e1 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "dependencies": { "graphql": "^15.5.0", "graphql-request": "^3.4.0", - "luxon": "^1.26.0" + "luxon": "^1.26.0", + "object-hash": "^2.1.1" }, "devDependencies": { "ava": "^3.15.0", diff --git a/source/connector-mobilizon/changelog.txt b/source/connector-mobilizon/changelog.txt index 1c82748..8d30f1f 100644 --- a/source/connector-mobilizon/changelog.txt +++ b/source/connector-mobilizon/changelog.txt @@ -1,6 +1,7 @@ ### [Unreleased] #### Added - Donation link to WordPress Plugin Directory sidebar and to `package.json` +- Cache requests for 2 minutes #### Changed - Update luxon dependency - Update dev dependencies jsdom, webpack, webpack-cli diff --git a/source/connector-mobilizon/front/date-time-wrapper-test.js b/source/connector-mobilizon/front/date-time-wrapper-test.js index 469a7ca..04b4969 100644 --- a/source/connector-mobilizon/front/date-time-wrapper-test.js +++ b/source/connector-mobilizon/front/date-time-wrapper-test.js @@ -1,5 +1,5 @@ -import test from 'ava'; -import { DateTimeWrapper } from './date-time-wrapper'; +import test from 'ava' +import { DateTimeWrapper } from './date-time-wrapper' test('#getShortDate usual date', t => { const d = new DateTimeWrapper('2020-12-24T16:45:00Z') diff --git a/source/connector-mobilizon/front/date-time-wrapper.js b/source/connector-mobilizon/front/date-time-wrapper.js index 6a204c2..5f99de3 100644 --- a/source/connector-mobilizon/front/date-time-wrapper.js +++ b/source/connector-mobilizon/front/date-time-wrapper.js @@ -1,4 +1,4 @@ -import { DateTime } from 'luxon'; +import { DateTime } from 'luxon' export class DateTimeWrapper { @@ -23,6 +23,6 @@ export class DateTimeWrapper { } static getCurrentDatetimeAsString() { - return DateTime.local().toString(); + return DateTime.local().toString() } } diff --git a/source/connector-mobilizon/front/events-loader.js b/source/connector-mobilizon/front/events-loader.js index a39ab1f..3d6d142 100644 --- a/source/connector-mobilizon/front/events-loader.js +++ b/source/connector-mobilizon/front/events-loader.js @@ -1,8 +1,8 @@ -import { DateTimeWrapper } from './date-time-wrapper'; +import { DateTimeWrapper } from './date-time-wrapper' import * as GraphqlWrapper from './graphql-wrapper' import * as HtmlCreator from './html-creator' -const NAME = ''; +const NAME = '' function displayEvents(data, list) { const maxEventsCount = list.getAttribute('data-maximum') @@ -11,7 +11,7 @@ function displayEvents(data, list) { for (let i = 0; i < eventsCount; i++) { const li = document.createElement('li') - const a = HtmlCreator.createAnchorElement({ text: events[i].title, url: events[i].url }); + const a = HtmlCreator.createAnchorElement({ text: events[i].title, url: events[i].url }) li.appendChild(a) const br = document.createElement('br') @@ -26,7 +26,7 @@ function displayEvents(data, list) { dateText += endsOn.getShortDate() + ' ' } dateText += endsOn.get24Time() - const textnode = document.createTextNode(dateText); + const textnode = document.createTextNode(dateText) li.appendChild(textnode) list.appendChild(li) @@ -44,7 +44,7 @@ document.addEventListener('DOMContentLoaded', () => { const eventLists = document.getElementsByClassName(NAME + '_events-list') for (let list of eventLists) { const url = list.getAttribute('data-url') + '/api' - const limit = list.getAttribute('data-maximum') + const limit = parseInt(list.getAttribute('data-maximum')) const groupName = list.getAttribute('data-group-name') if (groupName) { GraphqlWrapper.getUpcomingEventsByGroupName({ url, limit, groupName }) diff --git a/source/connector-mobilizon/front/graphql-wrapper.js b/source/connector-mobilizon/front/graphql-wrapper.js index 017cc6b..b2f291f 100644 --- a/source/connector-mobilizon/front/graphql-wrapper.js +++ b/source/connector-mobilizon/front/graphql-wrapper.js @@ -1,30 +1,11 @@ -import { request, gql } from 'graphql-request' +import { SessionCache } from './session-cache' +import { request } from 'graphql-request' import { DateTimeWrapper } from './date-time-wrapper' export function getUpcomingEvents({ url, limit }) { - const query = gql` - query { - events(limit:${limit}) { - elements { - id, - title, - url, - beginsOn, - endsOn - }, - total - } - } - ` - return request(url, query) -} - -export function getUpcomingEventsByGroupName({ url, limit, groupName }) { - const afterDatetime = DateTimeWrapper.getCurrentDatetimeAsString(); - const query = gql` - query { - group(preferredUsername:"${groupName}") { - organizedEvents(afterDatetime:"${afterDatetime}", limit:${limit}) { + const query = ` + query ($limit: Int) { + events(limit: $limit) { elements { id, title, @@ -35,7 +16,41 @@ export function getUpcomingEventsByGroupName({ url, limit, groupName }) { total } } - } ` - return request(url, query) + const dataInCache = SessionCache.get({ url, query, variables: { limit }}) + if (dataInCache !== null) + return Promise.resolve(dataInCache) + return request(url, query, { limit }) + .then((data) => { + SessionCache.add({ url, query, variables: { limit }}, data) + return Promise.resolve(data) + }) +} + +export function getUpcomingEventsByGroupName({ url, limit, groupName }) { + const query = ` + query ($afterDatetime: DateTime, $groupName: String, $limit: Int) { + group(preferredUsername: $groupName) { + organizedEvents(afterDatetime: $afterDatetime, limit: $limit) { + elements { + id, + title, + url, + beginsOn, + endsOn + }, + total + } + } + } + ` + const afterDatetime = DateTimeWrapper.getCurrentDatetimeAsString() + const dataInCache = SessionCache.get({ url, query, variables: { afterDatetime, groupName, limit }}) + if (dataInCache !== null) + return Promise.resolve(dataInCache) + return request(url, query, { afterDatetime, groupName, limit }) + .then((data) => { + SessionCache.add({ url, query, variables: { afterDatetime, groupName, limit }}, data) + return Promise.resolve(data) + }) } diff --git a/source/connector-mobilizon/front/html-creator-test.js b/source/connector-mobilizon/front/html-creator-test.js index ade57ef..b97d32f 100644 --- a/source/connector-mobilizon/front/html-creator-test.js +++ b/source/connector-mobilizon/front/html-creator-test.js @@ -1,7 +1,7 @@ -import test from 'ava'; -import { JSDOM } from 'jsdom'; +import test from 'ava' +import { JSDOM } from 'jsdom' -import * as HtmlCreator from './html-creator'; +import * as HtmlCreator from './html-creator' test.beforeEach(() => { global.document = new JSDOM().window.document diff --git a/source/connector-mobilizon/front/object-hash-wrapper-test.js b/source/connector-mobilizon/front/object-hash-wrapper-test.js new file mode 100644 index 0000000..b7ac52d --- /dev/null +++ b/source/connector-mobilizon/front/object-hash-wrapper-test.js @@ -0,0 +1,6 @@ +import test from 'ava' +import { hash } from './object-hash-wrapper' + +test('#hash object', t => { + t.is(hash({foo: 'bar'}), 'a75c05bdca7d704bdfcd761913e5a4e4636e956b') +}) diff --git a/source/connector-mobilizon/front/object-hash-wrapper.js b/source/connector-mobilizon/front/object-hash-wrapper.js new file mode 100644 index 0000000..262f85f --- /dev/null +++ b/source/connector-mobilizon/front/object-hash-wrapper.js @@ -0,0 +1,5 @@ +import objectHash from 'object-hash' + +export default function hash(object) { + return objectHash(object) +} diff --git a/source/connector-mobilizon/front/session-cache.js b/source/connector-mobilizon/front/session-cache.js new file mode 100644 index 0000000..78d7383 --- /dev/null +++ b/source/connector-mobilizon/front/session-cache.js @@ -0,0 +1,24 @@ +import hash from './object-hash-wrapper' + +const MAX_AGE_IN_MS = 120000 + +export class SessionCache { + + static add(parameters, data) { + const key = hash(parameters) + const timestamp = Date.now() + const value = { + data, + timestamp, + } + sessionStorage.setItem(key, JSON.stringify(value)) + } + + static get(parameters) { + const key = hash(parameters) + const value = JSON.parse(sessionStorage.getItem(key)) + if (value.timestamp && value.timestamp > Date.now() - MAX_AGE_IN_MS) + return value.data + return null + } +}