Files
fluxer/fluxer_api/src/models/ScheduledMessage.ts
Hampus Kraft 2f557eda8c initial commit
2026-01-01 21:05:54 +00:00

199 lines
6.0 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 type {ChannelID, MessageID, UserID} from '~/BrandedTypes';
import type {AttachmentRequestData} from '~/channel/AttachmentDTOs';
import type {AllowedMentionsRequest, MessageRequest} from '~/channel/ChannelModel';
import type {ScheduledMessageRow} from '~/database/CassandraTypes';
export type ScheduledMessageStatus = 'pending' | 'invalid';
export interface ScheduledMessageReference {
message_id: string;
channel_id?: string;
guild_id?: string;
type?: number;
}
export interface ScheduledAllowedMentions {
parse?: AllowedMentionsRequest['parse'];
users?: Array<string>;
roles?: Array<string>;
replied_user?: boolean;
}
export interface ScheduledMessagePayload {
content?: string | null;
embeds?: MessageRequest['embeds'];
attachments?: Array<AttachmentRequestData>;
message_reference?: ScheduledMessageReference;
allowed_mentions?: ScheduledAllowedMentions;
flags?: number;
nonce?: string;
favorite_meme_id?: string;
sticker_ids?: Array<string>;
tts?: boolean;
}
export interface ScheduledMessageResponse {
id: string;
channel_id: string;
scheduled_at: string;
scheduled_local_at: string;
timezone: string;
status: ScheduledMessageStatus;
status_reason: string | null;
payload: ScheduledMessagePayload;
created_at: string;
invalidated_at: string | null;
}
export class ScheduledMessage {
readonly userId: UserID;
readonly id: MessageID;
readonly channelId: ChannelID;
readonly scheduledAt: Date;
readonly scheduledLocalAt: string;
readonly timezone: string;
readonly payload: ScheduledMessagePayload;
readonly status: ScheduledMessageStatus;
readonly statusReason: string | null;
readonly createdAt: Date;
readonly invalidatedAt: Date | null;
constructor(params: {
userId: UserID;
id: MessageID;
channelId: ChannelID;
scheduledAt: Date;
scheduledLocalAt: string;
timezone: string;
payload: ScheduledMessagePayload;
status?: ScheduledMessageStatus;
statusReason?: string | null;
createdAt?: Date;
invalidatedAt?: Date | null;
}) {
this.userId = params.userId;
this.id = params.id;
this.channelId = params.channelId;
this.scheduledAt = params.scheduledAt;
this.scheduledLocalAt = params.scheduledLocalAt;
this.timezone = params.timezone;
this.payload = params.payload;
this.status = params.status ?? 'pending';
this.statusReason = params.statusReason ?? null;
this.createdAt = params.createdAt ?? new Date();
this.invalidatedAt = params.invalidatedAt ?? null;
}
static fromRow(row: ScheduledMessageRow): ScheduledMessage {
return new ScheduledMessage({
userId: row.user_id,
id: row.scheduled_message_id,
channelId: row.channel_id,
scheduledAt: row.scheduled_at,
scheduledLocalAt: row.scheduled_local_at,
timezone: row.timezone,
payload: parsePayload(row.payload),
status: toStatus(row.status),
statusReason: row.status_reason,
createdAt: row.created_at,
invalidatedAt: row.invalidated_at,
});
}
toRow(): ScheduledMessageRow {
return {
user_id: this.userId,
scheduled_message_id: this.id,
channel_id: this.channelId,
payload: JSON.stringify(this.payload),
scheduled_at: this.scheduledAt,
scheduled_local_at: this.scheduledLocalAt,
timezone: this.timezone,
status: this.status,
status_reason: this.statusReason,
created_at: this.createdAt,
invalidated_at: this.invalidatedAt,
};
}
toResponse(): ScheduledMessageResponse {
return {
id: this.id.toString(),
channel_id: this.channelId.toString(),
scheduled_at: this.scheduledAt.toISOString(),
scheduled_local_at: this.scheduledLocalAt,
timezone: this.timezone,
status: this.status,
status_reason: this.statusReason,
payload: this.payload,
created_at: this.createdAt.toISOString(),
invalidated_at: this.invalidatedAt?.toISOString() ?? null,
};
}
parseToMessageRequest(): MessageRequest {
return hydrateMessageRequest(this.payload);
}
}
function parsePayload(payload: string): ScheduledMessagePayload {
try {
return JSON.parse(payload) as ScheduledMessagePayload;
} catch (_error) {
return {};
}
}
function toStatus(value: string): ScheduledMessageStatus {
return value === 'invalid' ? 'invalid' : 'pending';
}
function hydrateMessageRequest(payload: ScheduledMessagePayload): MessageRequest {
const message: MessageRequest = {
content: payload.content,
embeds: payload.embeds ?? [],
attachments: payload.attachments,
message_reference: payload.message_reference
? {
...payload.message_reference,
message_id: BigInt(payload.message_reference.message_id),
channel_id: payload.message_reference.channel_id ? BigInt(payload.message_reference.channel_id) : undefined,
guild_id: payload.message_reference.guild_id ? BigInt(payload.message_reference.guild_id) : undefined,
}
: undefined,
allowed_mentions: payload.allowed_mentions
? {
parse: payload.allowed_mentions.parse,
users: payload.allowed_mentions.users?.map((value) => BigInt(value)),
roles: payload.allowed_mentions.roles?.map((value) => BigInt(value)),
replied_user: payload.allowed_mentions.replied_user,
}
: undefined,
flags: payload.flags,
nonce: payload.nonce,
favorite_meme_id: payload.favorite_meme_id ? BigInt(payload.favorite_meme_id) : undefined,
sticker_ids: payload.sticker_ids?.map((value) => BigInt(value)),
tts: payload.tts,
};
return message;
}