diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js --- a/keyserver/src/endpoints.js +++ b/keyserver/src/endpoints.js @@ -42,6 +42,7 @@ threadUpdateResponder, threadCreationResponder, threadJoinResponder, + threadFetchMediaResponder, } from './responders/thread-responders'; import { userSubscriptionUpdateResponder, @@ -133,6 +134,10 @@ responder: messageFetchResponder, requiredPolicies: baseLegalPolicies, }, + fetch_thread_media: { + responder: threadFetchMediaResponder, + requiredPolicies: baseLegalPolicies, + }, get_session_public_keys: { responder: getSessionPublicKeysResponder, requiredPolicies: baseLegalPolicies, diff --git a/keyserver/src/fetchers/upload-fetchers.js b/keyserver/src/fetchers/upload-fetchers.js --- a/keyserver/src/fetchers/upload-fetchers.js +++ b/keyserver/src/fetchers/upload-fetchers.js @@ -5,6 +5,7 @@ import type { Media } from 'lib/types/media-types'; import type { MediaMessageServerDBContent } from 'lib/types/messages/media.js'; import { getUploadIDsFromMediaMessageServerDBContents } from 'lib/types/messages/media.js'; +import type { ThreadFetchMediaResult } from 'lib/types/thread-types'; import { ServerError } from 'lib/utils/errors'; import { dbQuery, SQL } from '../database/database'; @@ -119,7 +120,7 @@ async function fetchMediaForThread( threadID: string, limit?: number, -): Promise<$ReadOnlyArray> { +): Promise { const limitQuery = limit ? SQL`LIMIT ${limit}` : SQL``; const query = SQL` SELECT id AS uploadID, secret AS uploadSecret, @@ -129,7 +130,9 @@ ORDER BY creation_time DESC `.append(limitQuery); const [uploads] = await dbQuery(query); - return uploads.map(mediaFromRow); + return { + media: uploads.map(mediaFromRow), + }; } async function fetchUploadsForMessage( diff --git a/keyserver/src/responders/thread-responders.js b/keyserver/src/responders/thread-responders.js --- a/keyserver/src/responders/thread-responders.js +++ b/keyserver/src/responders/thread-responders.js @@ -15,6 +15,8 @@ type NewThreadResponse, type ServerThreadJoinRequest, type ThreadJoinResult, + type ThreadFetchMediaResult, + type ThreadFetchMediaRequest, threadTypes, } from 'lib/types/thread-types'; import { values } from 'lib/utils/objects'; @@ -27,6 +29,7 @@ import { createThread } from '../creators/thread-creator'; import { deleteThread } from '../deleters/thread-deleters'; +import { fetchMediaForThread } from '../fetchers/upload-fetchers'; import type { Viewer } from '../session/viewer'; import { updateRole, @@ -176,6 +179,19 @@ return await joinThread(viewer, request); } +const threadFetchMediaRequestInputValidator = tShape({ + threadID: t.String, + limit: t.maybe(t.Number), +}); +async function threadFetchMediaResponder( + viewer: Viewer, + input: any, +): Promise { + const request: ThreadFetchMediaRequest = input; + await validateInput(viewer, threadFetchMediaRequestInputValidator, request); + return await fetchMediaForThread(request.threadID, request.limit); +} + export { threadDeletionResponder, roleUpdateResponder, @@ -184,5 +200,6 @@ threadUpdateResponder, threadCreationResponder, threadJoinResponder, + threadFetchMediaResponder, newThreadRequestInputValidator, }; diff --git a/lib/actions/thread-actions.js b/lib/actions/thread-actions.js --- a/lib/actions/thread-actions.js +++ b/lib/actions/thread-actions.js @@ -2,6 +2,7 @@ import invariant from 'invariant'; +import type { Media } from '../types/media-types'; import type { ChangeThreadSettingsPayload, LeaveThreadPayload, @@ -10,6 +11,7 @@ NewThreadResult, ClientThreadJoinRequest, ThreadJoinPayload, + ThreadFetchMediaRequest, } from '../types/thread-types'; import type { CallServerEndpoint } from '../utils/call-server-endpoint'; import { values } from '../utils/objects'; @@ -162,6 +164,15 @@ }; }; +const fetchThreadMedia = ( + callServerEndpoint: CallServerEndpoint, +): (( + request: ThreadFetchMediaRequest, +) => Promise<$ReadOnlyArray>) => async request => { + const response = await callServerEndpoint('fetch_thread_media', request); + return response.media; +}; + export { deleteThreadActionTypes, deleteThread, @@ -177,4 +188,5 @@ joinThread, leaveThreadActionTypes, leaveThread, + fetchThreadMedia, }; diff --git a/lib/types/endpoints.js b/lib/types/endpoints.js --- a/lib/types/endpoints.js +++ b/lib/types/endpoints.js @@ -61,6 +61,7 @@ FETCH_ENTRY_REVISIONS: 'fetch_entry_revisions', FETCH_ERROR_REPORT_INFOS: 'fetch_error_report_infos', FETCH_MESSAGES: 'fetch_messages', + FETCH_THREAD_MEDIA: 'fetch_thread_media', GET_SESSION_PUBLIC_KEYS: 'get_session_public_keys', JOIN_THREAD: 'join_thread', LEAVE_THREAD: 'leave_thread', diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js --- a/lib/types/thread-types.js +++ b/lib/types/thread-types.js @@ -4,6 +4,7 @@ import type { Shape } from './core'; import type { CalendarQuery, RawEntryInfo } from './entry-types'; +import type { Media } from './media-types'; import type { RawMessageInfo, MessageTruncationStatuses, @@ -434,6 +435,14 @@ +userInfos: $ReadOnlyArray, }; +export type ThreadFetchMediaResult = { + +media: $ReadOnlyArray, +}; +export type ThreadFetchMediaRequest = { + +threadID: string, + +limit?: number, +}; + export type SidebarInfo = { +threadInfo: ThreadInfo, +lastUpdatedTime: number,