Redirect to last day with message history (#65)

Redirect to last day with message history: `/:roomIdOrAlias` -> `/:roomIdOrAlias/date/:yyyy/:mm/:dd`

Fix https://github.com/matrix-org/matrix-public-archive/issues/60
This commit is contained in:
Eric Eastwood 2022-09-08 02:18:18 -05:00 committed by GitHub
parent 127d416e6a
commit 65a371910a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 7 deletions

View File

@ -4,6 +4,7 @@ const assert = require('assert');
const urlJoin = require('url-join'); const urlJoin = require('url-join');
const { fetchEndpointAsJson } = require('../fetch-endpoint'); const { fetchEndpointAsJson } = require('../fetch-endpoint');
const timestampToEvent = require('./timestamp-to-event');
const { traceFunction } = require('../../tracing/trace-utilities'); const { traceFunction } = require('../../tracing/trace-utilities');
const config = require('../config'); const config = require('../config');
@ -27,14 +28,12 @@ async function fetchEventsFromTimestampBackwards(accessToken, roomId, ts, limit)
assert(ts); assert(ts);
assert(limit); assert(limit);
const timestampToEventEndpoint = urlJoin( const { eventId: eventIdForTimestamp } = await timestampToEvent({
matrixServerUrl,
`_matrix/client/unstable/org.matrix.msc3030/rooms/${roomId}/timestamp_to_event?ts=${ts}&dir=b`
);
const timestampToEventResData = await fetchEndpointAsJson(timestampToEventEndpoint, {
accessToken, accessToken,
roomId,
ts,
direction: 'b',
}); });
const eventIdForTimestamp = timestampToEventResData.event_id;
assert(eventIdForTimestamp); assert(eventIdForTimestamp);
//console.log('eventIdForTimestamp', eventIdForTimestamp); //console.log('eventIdForTimestamp', eventIdForTimestamp);

View File

@ -28,7 +28,6 @@ async function fetchPublicRooms(accessToken, { server, paginationToken, limit }
matrixServerUrl, matrixServerUrl,
`_matrix/client/v3/publicRooms?${qs.toString()}` `_matrix/client/v3/publicRooms?${qs.toString()}`
); );
console.log('publicRoomsEndpoint', publicRoomsEndpoint);
const publicRoomsRes = await fetchEndpointAsJson(publicRoomsEndpoint, { const publicRoomsRes = await fetchEndpointAsJson(publicRoomsEndpoint, {
accessToken, accessToken,

View File

@ -0,0 +1,33 @@
'use strict';
const assert = require('assert');
const urlJoin = require('url-join');
const { fetchEndpointAsJson } = require('../fetch-endpoint');
const { traceFunction } = require('../../tracing/trace-utilities');
const config = require('../config');
const matrixServerUrl = config.get('matrixServerUrl');
assert(matrixServerUrl);
async function timestampToEvent({ accessToken, roomId, ts, direction }) {
assert(accessToken);
assert(roomId);
assert(ts);
assert(direction);
const timestampToEventEndpoint = urlJoin(
matrixServerUrl,
`_matrix/client/unstable/org.matrix.msc3030/rooms/${roomId}/timestamp_to_event?ts=${ts}&dir=${direction}`
);
const timestampToEventResData = await fetchEndpointAsJson(timestampToEventEndpoint, {
accessToken,
});
return {
eventId: timestampToEventResData.event_id,
originServerTs: timestampToEventResData.origin_server_ts,
};
}
module.exports = traceFunction(timestampToEvent);

View File

@ -12,7 +12,9 @@ const timeoutMiddleware = require('./timeout-middleware');
const fetchRoomData = require('../lib/matrix-utils/fetch-room-data'); const fetchRoomData = require('../lib/matrix-utils/fetch-room-data');
const fetchEventsInRange = require('../lib/matrix-utils/fetch-events-in-range'); const fetchEventsInRange = require('../lib/matrix-utils/fetch-events-in-range');
const ensureRoomJoined = require('../lib/matrix-utils/ensure-room-joined'); const ensureRoomJoined = require('../lib/matrix-utils/ensure-room-joined');
const timestampToEvent = require('../lib/matrix-utils/timestamp-to-event');
const renderHydrogenVmRenderScriptToPageHtml = require('../hydrogen-render/render-hydrogen-vm-render-script-to-page-html'); const renderHydrogenVmRenderScriptToPageHtml = require('../hydrogen-render/render-hydrogen-vm-render-script-to-page-html');
const MatrixPublicArchiveURLCreator = require('matrix-public-archive-shared/lib/url-creator');
const config = require('../lib/config'); const config = require('../lib/config');
const basePath = config.get('basePath'); const basePath = config.get('basePath');
@ -24,6 +26,8 @@ assert(matrixAccessToken);
const archiveMessageLimit = config.get('archiveMessageLimit'); const archiveMessageLimit = config.get('archiveMessageLimit');
assert(archiveMessageLimit); assert(archiveMessageLimit);
const matrixPublicArchiveURLCreator = new MatrixPublicArchiveURLCreator(basePath);
const router = express.Router({ const router = express.Router({
caseSensitive: true, caseSensitive: true,
// Preserve the req.params values from the parent router. // Preserve the req.params values from the parent router.
@ -73,6 +77,40 @@ function parseArchiveRangeFromReq(req) {
}; };
} }
router.get(
'/',
asyncHandler(async function (req, res) {
const roomIdOrAlias = req.params.roomIdOrAlias;
assert(roomIdOrAlias.startsWith('!') || roomIdOrAlias.startsWith('#'));
// In case we're joining a new room for the first time,
// let's avoid redirecting to our join event
const dateBeforeJoin = Date.now();
// We have to wait for the room join to happen first before we can fetch
// any of the additional room info or messages.
await ensureRoomJoined(matrixAccessToken, roomIdOrAlias, req.query.via);
// Find the closest day to today with messages
const { originServerTs } = await timestampToEvent({
accessToken: matrixAccessToken,
roomId: roomIdOrAlias,
ts: dateBeforeJoin,
direction: 'b',
});
if (!originServerTs) {
throw new StatusError(404, 'Unable to find day with an history');
}
// Redirect to a day with messages
res.redirect(
matrixPublicArchiveURLCreator.archiveUrlForDate(roomIdOrAlias, new Date(originServerTs), {
viaServers: req.query.via,
})
);
})
);
router.get( router.get(
'/event/:eventId', '/event/:eventId',
asyncHandler(async function (req, res) { asyncHandler(async function (req, res) {

View File

@ -160,6 +160,38 @@ describe('matrix-public-archive', () => {
return sendEvent(options); return sendEvent(options);
} }
it('redirects to last day with message history', async () => {
const client = await getTestClientForHs(testMatrixServerUrl1);
const roomId = await createTestRoom(client);
// Send an event in the room so we have some day of history to redirect to
const eventId = await sendMessageOnArchiveDate({
client,
roomId,
content: {
msgtype: 'm.text',
body: 'some message in the history',
},
});
const expectedEventIdsOnDay = [eventId];
// Visit `/:roomIdOrAlias` and expect to be redirected to the last day with events
archiveUrl = matrixPublicArchiveURLCreator.archiveUrlForRoom(roomId);
const archivePageHtml = await fetchEndpointAsText(archiveUrl);
const dom = parseHTML(archivePageHtml);
// Make sure the messages from the day we expect to get redirected to are visible
assert.deepStrictEqual(
expectedEventIdsOnDay.map((eventId) => {
return dom.document
.querySelector(`[data-event-id="${eventId}"]`)
?.getAttribute('data-event-id');
}),
expectedEventIdsOnDay
);
});
it('shows all events in a given day', async () => { it('shows all events in a given day', async () => {
const client = await getTestClientForHs(testMatrixServerUrl1); const client = await getTestClientForHs(testMatrixServerUrl1);
const roomId = await createTestRoom(client); const roomId = await createTestRoom(client);