Changeset View
Changeset View
Standalone View
Standalone View
keyserver/src/fetchers/message-fetchers.js
Show All 16 Lines | import { | ||||
type MessageType, | type MessageType, | ||||
type EditMessageContent, | type EditMessageContent, | ||||
assertMessageType, | assertMessageType, | ||||
type MessageSelectionCriteria, | type MessageSelectionCriteria, | ||||
type MessageTruncationStatus, | type MessageTruncationStatus, | ||||
messageTruncationStatus, | messageTruncationStatus, | ||||
type FetchMessageInfosResult, | type FetchMessageInfosResult, | ||||
defaultMaxMessageAge, | defaultMaxMessageAge, | ||||
type FetchPinnedMessagesRequest, | |||||
type FetchPinnedMessagesResult, | |||||
} from 'lib/types/message-types.js'; | } from 'lib/types/message-types.js'; | ||||
import { threadPermissions } from 'lib/types/thread-types.js'; | import { threadPermissions } from 'lib/types/thread-types.js'; | ||||
import { ServerError } from 'lib/utils/errors.js'; | import { ServerError } from 'lib/utils/errors.js'; | ||||
import { | import { | ||||
constructMediaFromMediaMessageContentsAndUploadRows, | constructMediaFromMediaMessageContentsAndUploadRows, | ||||
imagesFromRow, | imagesFromRow, | ||||
} from './upload-fetchers.js'; | } from './upload-fetchers.js'; | ||||
▲ Show 20 Lines • Show All 622 Lines • ▼ Show 20 Lines | const query = SQL` | ||||
LEFT JOIN memberships stm ON m.type = ${messageTypes.CREATE_SUB_THREAD} | LEFT JOIN memberships stm ON m.type = ${messageTypes.CREATE_SUB_THREAD} | ||||
AND stm.thread = m.content AND stm.user = m.user | AND stm.thread = m.content AND stm.user = m.user | ||||
WHERE m.id IN (${messageIDs}) | WHERE m.id IN (${messageIDs}) | ||||
`; | `; | ||||
const [result] = await dbQuery(query); | const [result] = await dbQuery(query); | ||||
return result; | return result; | ||||
} | } | ||||
async function fetchPinnedMessageInfos( | |||||
viewer: Viewer, | |||||
request: FetchPinnedMessagesRequest, | |||||
): Promise<FetchPinnedMessagesResult> { | |||||
// The only message types that can be pinned are 0, 14, and 15 | |||||
// (text, images, and multimedia), so we don't need to worry about | |||||
// an admin pinning a message about creating a secret subchannel. This is | |||||
// why we don't check subthread permissions (as opposed to other queries). | |||||
const messageRowsQuery = SQL` | |||||
SELECT m.id, m.thread AS threadID, m.content, m.time, m.type, m.creation, | |||||
m.user AS creatorID, m.target_message as targetMessageID, | |||||
NULL AS subthread_permissions, u.id AS uploadID, | |||||
u.type AS uploadType, u.secret AS uploadSecret, u.extra AS uploadExtra | |||||
FROM messages m | |||||
LEFT JOIN uploads u ON u.container = m.id | |||||
LEFT JOIN memberships mm ON mm.thread = m.thread AND mm.user = ${viewer.id} | |||||
WHERE m.thread = ${request.threadID} | |||||
AND m.pinned = 1 | |||||
AND JSON_EXTRACT(mm.permissions, ${visibleExtractString}) IS TRUE | |||||
ORDER BY m.pin_time DESC | |||||
`; | |||||
const [messageRows] = await dbQuery(messageRowsQuery); | |||||
if (messageRows.length === 0) { | |||||
return { pinnedMessages: [] }; | |||||
} | |||||
const derivedMessages = await fetchDerivedMessages(messageRows, viewer); | |||||
const parsedPinnedMessages = await parseMessageSQLResult( | |||||
messageRows, | |||||
derivedMessages, | |||||
viewer, | |||||
); | |||||
const pinnedRawMessageInfos = parsedPinnedMessages.map( | |||||
message => message.rawMessageInfo, | |||||
); | |||||
const shimmedPinnedRawMessageInfos = shimUnsupportedRawMessageInfos( | |||||
pinnedRawMessageInfos, | |||||
viewer.platformDetails, | |||||
); | |||||
return { | |||||
pinnedMessages: shimmedPinnedRawMessageInfos, | |||||
}; | |||||
} | |||||
async function fetchDerivedMessages( | async function fetchDerivedMessages( | ||||
rows: $ReadOnlyArray<Object>, | rows: $ReadOnlyArray<Object>, | ||||
viewer?: Viewer, | viewer?: Viewer, | ||||
): Promise< | ): Promise< | ||||
$ReadOnlyMap<string, RawComposableMessageInfo | RawRobotextMessageInfo>, | $ReadOnlyMap<string, RawComposableMessageInfo | RawRobotextMessageInfo>, | ||||
> { | > { | ||||
const requiredIDs = new Set<string>(); | const requiredIDs = new Set<string>(); | ||||
for (const row of rows) { | for (const row of rows) { | ||||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Lines | export { | ||||
fetchMessageInfos, | fetchMessageInfos, | ||||
fetchMessageInfosSince, | fetchMessageInfosSince, | ||||
getMessageFetchResultFromRedisMessages, | getMessageFetchResultFromRedisMessages, | ||||
fetchMessageInfoForLocalID, | fetchMessageInfoForLocalID, | ||||
fetchMessageInfoForEntryAction, | fetchMessageInfoForEntryAction, | ||||
fetchMessageInfoByID, | fetchMessageInfoByID, | ||||
fetchThreadMessagesCount, | fetchThreadMessagesCount, | ||||
fetchLatestEditMessageContentByID, | fetchLatestEditMessageContentByID, | ||||
fetchPinnedMessageInfos, | |||||
}; | }; |