Source

classes/message.ts

import Snowflake from "./snowflake";
import UserClient from "./userClient";
import User from "./user";
import { SnowflakeString } from "../types/snowflake";
import { RequestContext, RequestContextWithClient } from "./requestContext";
import { UserType } from "../types/basicUser";
import { MessageState } from "../types/message";
import {
    DBMessage, DBMessageFull, DBMessageWithAuthor, DBMessageWithTarget, prisma
} from "../../prisma";

/**
 * Holds message data
 */
class Message {
    id: Snowflake;
    ctx: RequestContext;
    client: UserClient;

    author: User;
    target: User;
    content: string;
    state: MessageState;
    reported?: boolean;

    /**
     * Creates new message data holder
     * @param {object} data
     */
    constructor({
        id,
        ctx,
        author,
        target,
        content,
        state,
        reported
    }: {
        id: Snowflake,
        ctx: RequestContextWithClient,
        author: User,
        target: User,
        content: string,
        state: MessageState,
        reported?: boolean
    }) {
        this.id = id;
        this.ctx = ctx;
        this.client = ctx.client;
        this.author = author;
        this.target = target;
        this.content = content;
        this.state = state;
        this.reported = reported;
    }

    /**
     * @param {DBMessage | DBMessageWithAuthor | DBMessageWithTarget | DBMessageFull} data
     * @param {RequestContextWithClient} ctx
     * @return {Promise<Message>}
     */
    static async fromDatabase(data: DBMessage | DBMessageWithAuthor |
        DBMessageWithTarget | DBMessageFull, ctx: RequestContextWithClient): Promise<Message> {
        if(
            data.targetId !== ctx.client.user.id.toBigInt() &&
            data.authorId !== ctx.client.user.id.toBigInt() &&
            ctx.client.user.type < UserType.MODERATOR
        ) {
            throw new Error("Message not found");
        }

        return new Message({
            id: new Snowflake(data.snowflake),
            ctx,
            author: "author" in data ?
                await User.fromDatabase(data.author, ctx) :
                await User.getUser(data.authorId, ctx),
            target: "target" in data ?
                await User.fromDatabase(data.target, ctx) :
                await User.getUser(data.targetId, ctx),
            content: data.content,
            state: data.state
        });
    }

    /**
     * Updates the message content
     * @return {Promise<void>}
     */
    async update(): Promise<void> {
        await prisma.message.update({
            where: {
                snowflake: this.id.toBigInt()
            },
            data: {
                content: this.content,
                state: this.state
            }
        });
    }

    /**
     * Deletes the message
     * @return {Promise<void>}
     */
    delete(): Promise<void> {
        this.state = MessageState.DELETED;
        return this.update();
    }

    /**
     * Fetches given message
     * @param {SnowflakeString | bigint} id
     * @param {RequestContextWithClient} ctx
     * @param {UserClient} client
     * @return {Promise<Message>}
     */
    static async getMessage(id: SnowflakeString | bigint, ctx: RequestContextWithClient):
    Promise<Message> {
        const data = await prisma.message.findUniqueOrThrow({
            where: {
                snowflake: BigInt(id)
            }
        });

        const msg = await Message.fromDatabase(data, ctx);

        if(ctx.user) {
            const report = await prisma.modQueue.findUnique({
                where: {
                    resourceId_reporterId: {
                        resourceId: msg.id.toBigInt(),
                        reporterId: ctx.user.id.toBigInt()
                    }
                }
            });

            msg.reported = !!report;
        }

        return msg;
    }

    /**
     * Creates a JSON-compatible object
     * @return {Object}
     */
    toJSON() {
        return {
            id: this.id.getSnowflake(),
            time: this.id.time,
            author: this.author.toJSON(),
            target: this.target.toJSON(),
            content: this.content,
            state: this.state,
            reported: this.reported
        };
    }
}

export default Message;