Source

classes/userRelation.ts

import { UserRelationType } from "../types/userRelation";
import Snowflake from "./snowflake";
import User from "./user";
import { UserType } from "../types/basicUser";
import { RequestContext, RequestContextWithClient } from "./requestContext";
import {
    DBUserRelation, DBUserRelationAuthor, DBUserRelationFull, DBUserRelationTarget, prisma
} from "../../prisma";

/**
 * Holds data about user - user relation
 */
class UserRelation {
    id: Snowflake;
    ctx: RequestContext;

    author: User;
    target: User;
    type: UserRelationType;

    /**
     * creates new user-user relation data holder
     * @param {object} data
     */
    constructor({
        id,
        ctx,
        author,
        target,
        type
    }: {
        id: Snowflake,
        ctx: RequestContext,
        author: User,
        target: User,
        type: UserRelationType
    }) {
        this.id = id;
        this.ctx = ctx;
        this.author = author;
        this.target = target;
        this.type = type;
    }

    /**
     * @param {DBUserRelation | DBUserRelationAuthor
     * | DBUserRelationFull | DBUserRelationTarget} data
     * @param {RequestContext} ctx
     * @return {Promise<UserRelation>}
     */
    static async fromDatabase(
        data: DBUserRelation | DBUserRelationAuthor | DBUserRelationFull | DBUserRelationTarget,
        ctx: RequestContext) {
        return new UserRelation({
            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),
            type: data.type
        });
    }

    /**
     * Loads user relation
     * @param {User} target
     * @param {RequestContextWithClient} ctx
     * @return {Promise<UserRelation>}
     */
    static async load(target: User, ctx: RequestContextWithClient): Promise<UserRelation> {
        const res = await prisma.userRelation.findFirstOrThrow({
            where: {
                authorId: ctx.client.user.id.toBigInt(),
                targetId: target.id.toBigInt()
            }
        });

        return UserRelation.fromDatabase(res, ctx);
    }

    /**
     * Creates or updates a relation
     *
     * @param {User} target
     * @param {UserRelationType} type
     * @param {RequestContextWithClient} ctx
     * @return {Promise<UserRelation>}
     * @throws {Error} if client is not set
     */
    static async upsert(target: User, type: UserRelationType, ctx: RequestContextWithClient):
        Promise<UserRelation> {
        if(!ctx.client) throw new Error("perms");
        if(ctx.client.user.id.getSnowflake() !== target.id.getSnowflake()) {
            if(!ctx.client.user.comparePosition(UserType.MODERATOR)) {
                throw new Error("perms");
            }
        }

        const data = await prisma.userRelation.upsert({
            where: {
                authorId_targetId: {
                    authorId: ctx.client.user.id.toBigInt(),
                    targetId: target.id.toBigInt()
                }
            },
            update: {
                type
            },
            create: {
                snowflake: Snowflake.newSnowflake().toBigInt(),
                authorId: ctx.client.user.id.toBigInt(),
                targetId: target.id.toBigInt(),
                type
            }
        });

        return UserRelation.fromDatabase(data, ctx);
    }

    /**
     * Updates user relation
     * @return {Promise<void>}
     */
    async update(): Promise<void> {
        if(!this.ctx.client) throw new Error("perms");
        if(this.ctx.client.user.id.getSnowflake() !== this.author.id.getSnowflake()) {
            if(!this.ctx.client.user.comparePosition(UserType.MODERATOR)) {
                throw new Error("perms");
            }
        }
        await prisma.userRelation.update({
            where: {
                snowflake: this.id.toBigInt()
            },
            data: {
                type: this.type
            }
        });
    }

    /**
     * Deletes user relation
     * @return {Promise<void>}
     */
    async delete(): Promise<void> {
        if(!this.ctx.client) throw new Error("perms");
        if(this.ctx.client.user.id.getSnowflake() !== this.author.id.getSnowflake()) {
            if(!this.ctx.client.user.comparePosition(UserType.MODERATOR)) {
                throw new Error("perms");
            }
        }
        await prisma.userRelation.delete({
            where: {
                snowflake: this.id.toBigInt()
            }
        });
    }

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

export default UserRelation;