Source

classes/comment.ts

import { CommentState } from "../types/comments";
import Snowflake from "./snowflake";
import Animation, { BasicAnimation } from "./animation";
import User from "./user";
import { UserType } from "../types/basicUser";
import { SnowflakeResolvable } from "../types/snowflake";
import { RequestContext } from "./requestContext";
import {
    DBComment, DBCommentFull, DBCommentWithAnimation, DBCommentWithAuthor, prisma
} from "../../prisma";

/**
 * Comment data holder
 */
class Comment {
    id: Snowflake;
    ctx: RequestContext;

    animation: BasicAnimation;
    user: User;
    content: string;
    state: CommentState;
    reported?: boolean;

    /**
     * @param {object} data
     */
    constructor({
        id,
        ctx,
        animation,
        user,
        content,
        state,
        reported
    }: {
        id: Snowflake,
        ctx: RequestContext,
        animation: BasicAnimation,
        user: User,
        content: string,
        state: CommentState,
        reported?: boolean
    }) {
        this.id = id;
        this.ctx = ctx;
        this.animation = animation;
        this.user = user;
        this.content = content;
        this.state = state;
        this.reported = reported;
    }

    /**
     * @param {any} data
     * @param {RequestContext} ctx
     * @return {Promise<Comment>}
     */
    static async fromDatabase(
        data: (DBComment | DBCommentFull | DBCommentWithAnimation | DBCommentWithAuthor) &
        { reported?: boolean },
        ctx: RequestContext
    ): Promise<Comment> {
        return new Comment({
            ctx,
            id: new Snowflake(data.snowflake),
            animation: "animation" in data ?
                await Animation.fromDatabase(data.animation, ctx) :
                await Animation.getAnimation(data.animationId, ctx),
            user: "author" in data ?
                await User.fromDatabase(data.author, ctx) :
                await User.getUser(data.authorId, ctx),
            content: data.content,
            state: data.state,
            reported: "reported" in data ? data.reported : undefined
        });
    }

    /**
     * @param {SnowflakeResolvable} id
     * @param {RequestContext} ctx
     * @return {Promise<Comment>}
     */
    static async getComment(id: SnowflakeResolvable, ctx: RequestContext):
        Promise<Comment> {
        const res = await prisma.comment.findUniqueOrThrow({
            where: {
                snowflake: (new Snowflake(id)).toBigInt()
            },
            include: {
                animation: true,
                author: true
            }
        });

        const comment = await Comment.fromDatabase(res, ctx);

        if(
            comment.state !== CommentState.NORMAL &&
            !ctx.client?.user.comparePosition(UserType.MODERATOR)
        ) {
            throw new Error("deleted");
        }

        if(ctx.user) {
            const reported = await prisma.modQueue.findFirst({
                where: {
                    resourceId: (new Snowflake(id)).toBigInt(),
                    reporterId: ctx.user.id.toBigInt()
                }
            });
            comment.reported = reported !== null;
        }

        return comment;
    }

    /**
     * Updates comment data
     * @return {Promise<void>}
     */
    async update(): Promise<void> {
        if(!this.ctx.client) throw new Error("unauthorized");
        if(!this.ctx.client.user.comparePosition(UserType.MODERATOR)) {
            throw new Error("unauthorized");
        }
        await prisma.comment.update({
            where: {
                snowflake: this.id.toBigInt()
            },
            data: {
                content: this.content,
                state: this.state
            }
        });
    }

    /**
     * Deletes comment
     * @return {Promise<void>}
     */
    delete(): Promise<void> {
        if(!this.ctx.client) throw new Error("unauthorized");
        if(!this.ctx.client.user.comparePosition(UserType.MODERATOR)) {
            throw new Error("unauthorized");
        }
        if(this.state !== CommentState.NORMAL) throw new Error("already_deleted");
        this.state = CommentState.MODERATOR_DELETED;
        return this.update();
    }

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

export default Comment;