diff --git a/keyserver/src/endpoints.js b/keyserver/src/endpoints.js --- a/keyserver/src/endpoints.js +++ b/keyserver/src/endpoints.js @@ -41,6 +41,7 @@ threadLeaveResponder, threadUpdateResponder, threadCreationResponder, + threadFetchMediaResponder, threadJoinResponder, } from './responders/thread-responders.js'; import { @@ -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 @@ -6,7 +6,10 @@ import type { MediaMessageServerDBContent } from 'lib/types/messages/media.js'; import { getUploadIDsFromMediaMessageServerDBContents } from 'lib/types/messages/media.js'; import { ServerError } from 'lib/utils/errors.js'; - +import type { + ThreadFetchMediaResult, + ThreadFetchMediaRequest, +} from 'lib/types/thread-types.js'; import { dbQuery, SQL } from '../database/database.js'; import type { Viewer } from '../session/viewer.js'; import { getAndAssertCommAppURLFacts } from '../utils/urls.js'; @@ -117,23 +120,20 @@ } async function fetchMediaForThread( - threadID: string, - limit: number, - offset: number, -): Promise<$ReadOnlyArray> { - const limitQuery = SQL`LIMIT ${limit} `; - const offsetQuery = SQL`OFFSET ${offset} `; + request: ThreadFetchMediaRequest, +): Promise { const query = SQL` SELECT id AS uploadID, secret AS uploadSecret, type AS uploadType, extra AS uploadExtra FROM uploads - WHERE thread = ${threadID} AND filename NOT LIKE 'thumb%' + WHERE thread = ${request.threadID} AND filename NOT LIKE 'thumb%' ORDER BY creation_time DESC - ` - .append(limitQuery) - .append(offsetQuery); + LIMIT ${request.limit} OFFSET ${request.offset} + `; 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.js'; import { values } from 'lib/utils/objects.js'; @@ -31,6 +33,7 @@ } from './entry-responders.js'; import { createThread } from '../creators/thread-creator.js'; import { deleteThread } from '../deleters/thread-deleters.js'; +import { fetchMediaForThread } from '../fetchers/upload-fetchers.js'; import type { Viewer } from '../session/viewer.js'; import { updateRole, @@ -176,6 +179,20 @@ return await joinThread(viewer, request); } +const threadFetchMediaRequestInputValidator = tShape({ + threadID: t.String, + limit: t.Number, + offset: t.Number, +}); +async function threadFetchMediaResponder( + viewer: Viewer, + input: any, +): Promise { + const request: ThreadFetchMediaRequest = input; + await validateInput(viewer, threadFetchMediaRequestInputValidator, request); + return await fetchMediaForThread(request); +} + export { threadDeletionResponder, roleUpdateResponder, @@ -184,5 +201,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 @@ -10,6 +10,8 @@ NewThreadResult, ClientThreadJoinRequest, ThreadJoinPayload, + ThreadFetchMediaRequest, + ThreadFetchMediaResult, } from '../types/thread-types.js'; import type { CallServerEndpoint } from '../utils/call-server-endpoint.js'; import { values } from '../utils/objects.js'; @@ -162,6 +164,15 @@ }; }; +const fetchThreadMedia = ( + callServerEndpoint: CallServerEndpoint, +): (( + request: ThreadFetchMediaRequest, +) => Promise) => async request => { + const response = await callServerEndpoint('fetch_thread_media', request); + return response; +}; + 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 @@ -8,6 +8,7 @@ RawMessageInfo, MessageTruncationStatuses, } from './message-types.js'; +import type { Media } from './media-types.js'; import type { ThreadSubscription } from './subscription-types.js'; import type { ServerUpdateInfo, ClientUpdateInfo } from './update-types.js'; import type { UserInfo, UserInfos } from './user-types.js'; @@ -453,6 +454,15 @@ +userInfos: $ReadOnlyArray, }; +export type ThreadFetchMediaResult = { + +media: $ReadOnlyArray, +}; +export type ThreadFetchMediaRequest = { + +threadID: string, + +limit: number, + +offset: number, +}; + export type SidebarInfo = { +threadInfo: ThreadInfo, +lastUpdatedTime: number,