Files
fluxer/fluxer_app/src/utils/MessageRequestUtils.tsx
T

165 lines
4.1 KiB
TypeScript

/*
* Copyright (C) 2026 Fluxer Contributors
*
* This file is part of Fluxer.
*
* Fluxer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Fluxer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
*/
import {MessageFlags} from '@fluxer/constants/src/ChannelConstants';
import type {
AllowedMentions,
MessageReference,
MessageStickerItem,
} from '@fluxer/schema/src/domains/message/MessageResponseSchemas';
const DEFAULT_ALLOWED_MENTIONS: AllowedMentions = {replied_user: true};
export interface ApiAttachmentMetadata {
id: string;
filename: string;
title: string;
description?: string;
flags?: number;
duration?: number;
waveform?: string;
}
export interface MessageCreateRequest {
content?: string | null;
nonce?: string;
attachments?: Array<ApiAttachmentMetadata>;
allowed_mentions?: AllowedMentions;
message_reference?: MessageReference;
flags?: number;
favorite_meme_id?: string;
sticker_ids?: Array<string>;
tts?: true;
}
export interface MessageEditRequest {
content?: string;
attachments?: Array<ApiAttachmentMetadata>;
flags?: number;
}
export interface MessageCreatePayload {
content?: string | null;
nonce?: string;
attachments?: Array<ApiAttachmentMetadata>;
allowedMentions?: AllowedMentions;
messageReference?: MessageReference;
flags?: number;
favoriteMemeId?: string;
stickers?: Array<MessageStickerItem>;
tts?: boolean;
}
export interface NormalizedMessageContent {
content: string;
flags: number;
}
export function normalizeMessageContent(content: string, favoriteMemeId?: string): NormalizedMessageContent {
const sanitized = removeSilentFlag(content);
const flags = getMessageFlags(content, favoriteMemeId);
return {content: sanitized, flags};
}
export function buildMessageCreateRequest(payload: MessageCreatePayload): MessageCreateRequest {
const {content, nonce, attachments, allowedMentions, messageReference, flags, favoriteMemeId, stickers, tts} =
payload;
const requestBody: MessageCreateRequest = {};
if (content != null && content.length > 0) {
requestBody.content = content;
}
if (nonce != null) {
requestBody.nonce = nonce;
}
if (attachments?.length) {
requestBody.attachments = attachments;
}
if (messageReference != null || shouldIncludeAllowedMentions(allowedMentions)) {
requestBody.allowed_mentions = allowedMentions;
}
if (messageReference) {
requestBody.message_reference = messageReference;
}
if (flags != null) {
requestBody.flags = flags;
}
if (favoriteMemeId) {
requestBody.favorite_meme_id = favoriteMemeId;
}
if (stickers?.length) {
requestBody.sticker_ids = stickers.map((sticker) => sticker.id);
}
if (tts) {
requestBody.tts = true;
}
return requestBody;
}
const isSilentMessage = (content: string): boolean => {
return content.startsWith('@silent ');
};
const removeSilentFlag = (content: string): string => {
return content.startsWith('@silent ') ? content.replace('@silent ', '') : content;
};
const getMessageFlags = (content: string, favoriteMemeId?: string): number => {
let flags = 0;
if (isSilentMessage(content)) {
flags |= MessageFlags.SUPPRESS_NOTIFICATIONS;
}
if (favoriteMemeId) {
flags |= MessageFlags.COMPACT_ATTACHMENTS;
}
return flags;
};
const shouldIncludeAllowedMentions = (allowedMentions?: AllowedMentions): boolean => {
if (!allowedMentions) {
return false;
}
const allowedKeys = Object.keys(allowedMentions) as Array<keyof AllowedMentions>;
if (allowedKeys.length !== Object.keys(DEFAULT_ALLOWED_MENTIONS).length) {
return true;
}
for (const key of allowedKeys) {
if (allowedMentions[key] !== DEFAULT_ALLOWED_MENTIONS[key]) {
return true;
}
}
return false;
};