diff --git a/server/lib/matrix-utils/fetch-events-in-range.js b/server/lib/matrix-utils/fetch-events-in-range.js index dbe7765..c474cb8 100644 --- a/server/lib/matrix-utils/fetch-events-in-range.js +++ b/server/lib/matrix-utils/fetch-events-in-range.js @@ -4,6 +4,7 @@ const assert = require('assert'); const urlJoin = require('url-join'); const { fetchEndpointAsJson } = require('../fetch-endpoint'); +const timestampToEvent = require('./timestamp-to-event'); const { traceFunction } = require('../../tracing/trace-utilities'); const config = require('../config'); @@ -27,14 +28,12 @@ async function fetchEventsFromTimestampBackwards(accessToken, roomId, ts, limit) assert(ts); assert(limit); - const timestampToEventEndpoint = urlJoin( - matrixServerUrl, - `_matrix/client/unstable/org.matrix.msc3030/rooms/${roomId}/timestamp_to_event?ts=${ts}&dir=b` - ); - const timestampToEventResData = await fetchEndpointAsJson(timestampToEventEndpoint, { + const { eventId: eventIdForTimestamp } = await timestampToEvent({ accessToken, + roomId, + ts, + direction: 'b', }); - const eventIdForTimestamp = timestampToEventResData.event_id; assert(eventIdForTimestamp); //console.log('eventIdForTimestamp', eventIdForTimestamp); diff --git a/server/lib/matrix-utils/fetch-public-rooms.js b/server/lib/matrix-utils/fetch-public-rooms.js index 35cb191..9530563 100644 --- a/server/lib/matrix-utils/fetch-public-rooms.js +++ b/server/lib/matrix-utils/fetch-public-rooms.js @@ -28,7 +28,6 @@ async function fetchPublicRooms(accessToken, { server, paginationToken, limit } matrixServerUrl, `_matrix/client/v3/publicRooms?${qs.toString()}` ); - console.log('publicRoomsEndpoint', publicRoomsEndpoint); const publicRoomsRes = await fetchEndpointAsJson(publicRoomsEndpoint, { accessToken, diff --git a/server/lib/matrix-utils/timestamp-to-event.js b/server/lib/matrix-utils/timestamp-to-event.js new file mode 100644 index 0000000..50f49ff --- /dev/null +++ b/server/lib/matrix-utils/timestamp-to-event.js @@ -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); diff --git a/server/routes/room-routes.js b/server/routes/room-routes.js index 5aae499..ad27056 100644 --- a/server/routes/room-routes.js +++ b/server/routes/room-routes.js @@ -12,7 +12,9 @@ const timeoutMiddleware = require('./timeout-middleware'); const fetchRoomData = require('../lib/matrix-utils/fetch-room-data'); const fetchEventsInRange = require('../lib/matrix-utils/fetch-events-in-range'); 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 MatrixPublicArchiveURLCreator = require('matrix-public-archive-shared/lib/url-creator'); const config = require('../lib/config'); const basePath = config.get('basePath'); @@ -24,6 +26,8 @@ assert(matrixAccessToken); const archiveMessageLimit = config.get('archiveMessageLimit'); assert(archiveMessageLimit); +const matrixPublicArchiveURLCreator = new MatrixPublicArchiveURLCreator(basePath); + const router = express.Router({ caseSensitive: true, // 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( '/event/:eventId', asyncHandler(async function (req, res) { diff --git a/test/e2e-tests.js b/test/e2e-tests.js index 193c8fc..f824bd9 100644 --- a/test/e2e-tests.js +++ b/test/e2e-tests.js @@ -160,6 +160,38 @@ describe('matrix-public-archive', () => { 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 () => { const client = await getTestClientForHs(testMatrixServerUrl1); const roomId = await createTestRoom(client);