Discord-InterChat/InterChat

View on GitHub
src/managers/UserDbManager.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { RedisKeys } from '#utils/Constants.js';
import { cacheData, getCachedData } from '#utils/CacheUtils.js';
import db from '#utils/Db.js';
import { supportedLocaleCodes } from '#utils/Locale.js';
import { Prisma, UserData } from '@prisma/client';
import { Snowflake } from 'discord.js';
import type { ConvertDatesToString } from '#types/Utils.d.ts';

export default class UserDbManager {
  private async addToCache(entity: ConvertDatesToString<UserData> | UserData, expirySecs?: number) {
    await cacheData(`${RedisKeys.userData}:${entity.id}`, JSON.stringify(entity), expirySecs);
  }

  private serializeUserDates(user: ConvertDatesToString<UserData>): UserData {
    return {
      ...user,
      lastVoted: user.lastVoted ? new Date(user.lastVoted) : null,
    };
  }

  async getUser(id: Snowflake): Promise<UserData | null> {
    const results = await getCachedData(
      `${RedisKeys.userData}:${id}`,
      async () => await db.userData.findFirst({ where: { id } }),
    );

    if (!results.data) return null;
    if (!results.fromCache) this.addToCache(results.data);

    return this.serializeUserDates(results.data);
  }

  async getUserLocale(userOrId: string | UserData | null | undefined) {
    const dbUser = typeof userOrId === 'string' ? await this.getUser(userOrId) : userOrId;
    return (dbUser?.locale as supportedLocaleCodes | null | undefined) ?? 'en';
  }

  async createUser(data: Prisma.UserDataCreateInput) {
    const createdUser = await db.userData.create({ data });
    await this.addToCache(createdUser);
    return createdUser;
  }

  async updateUser(id: Snowflake, data: Prisma.UserDataUpdateInput) {
    const updatedUser = await db.userData.update({ where: { id }, data });
    await this.addToCache(updatedUser);
    return updatedUser;
  }

  async upsertUser(id: Snowflake, data: Omit<Prisma.UserDataUpsertArgs['create'], 'id'>) {
    const upsertedUser = await db.userData.upsert({
      where: { id },
      create: { ...data, id },
      update: data,
    });
    await this.addToCache(upsertedUser);
    return upsertedUser;
  }

  async userVotedToday(id: Snowflake): Promise<boolean> {
    const user = await this.getUser(id);
    const twenty4HoursAgo = new Date(Date.now() - 60 * 60 * 24 * 1000);
    return Boolean(user?.lastVoted && new Date(user.lastVoted) >= twenty4HoursAgo);
  }

  async ban(id: string, reason: string, username?: string) {
    const user = await this.upsertUser(id, {
      username,
      voteCount: 0,
      banMeta: { reason },
    });

    await this.addToCache(user);
  }

  async unban(id: string, username?: string) {
    const user = await this.upsertUser(id, {
      username,
      voteCount: 0,
      banMeta: { set: null },
    });

    await this.addToCache(user);
  }
}