63 lines
3 KiB
TypeScript
63 lines
3 KiB
TypeScript
import config from "@lib/config";
|
|
import TableService from "../TableService";
|
|
import { CUserContract } from "@lib/types/ContractTypes";
|
|
import { hashText } from "@lib/modules/auth/auth.service";
|
|
import { KeyPairType } from "@prisma/client";
|
|
import { UserErrors } from "@lib/vix/ClientErrors";
|
|
|
|
// prettier-ignore
|
|
const generateBase64Password = (length: number = 32): string => Array.from(crypto.getRandomValues(new Uint8Array(length)), byte => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.charAt(byte % 64)).join('');
|
|
|
|
export default class UsersTableService extends TableService {
|
|
protected table = "User";
|
|
async byId(userId: string) {
|
|
return this.pg.user.findUnique({ where: { id: userId }, include: { rolePolicy: true, project: true } });
|
|
}
|
|
|
|
async byUsername(username: string, projectId: string) {
|
|
return this.pg.user.findUnique({ where: { projectId_username: { projectId, username } } });
|
|
}
|
|
|
|
async byEmail(email: string, projectId: string) {
|
|
return this.pg.user.findUnique({ where: { projectId_email: { projectId, email } } });
|
|
}
|
|
|
|
async $upsertDefaultRootUser() {
|
|
const project = await this.pg.project.findUnique({ where: { slug: config.Server.projectSlug } });
|
|
if (!project) throw new Error("Cairo Project Not Found!");
|
|
const rolePolicyId = config.RolePolicy.Root.id;
|
|
return this.$upsertRootUser(project.id, rolePolicyId);
|
|
}
|
|
|
|
async $upsertRootUser(projectId: string, rolePolicyId: string) {
|
|
const root = await this.pg.user.findUnique({ where: { projectId_username: { username: "root", projectId } } });
|
|
if (!!root) return;
|
|
const password = config.Server.rootPassword ?? generateBase64Password();
|
|
const hash = await hashText(password);
|
|
const user = await this.pg.user.create({ data: { projectId, username: "root", email: "root", hash, rolePolicyId } });
|
|
return { ...user, password };
|
|
}
|
|
|
|
async create(options: CUserContract["Create"]) {
|
|
const { hash, projectId, rolePolicyId } = options;
|
|
const username = options.username?.toLowerCase();
|
|
const email = options.email?.toLowerCase() ?? undefined;
|
|
const [existingUsername, existingEmail] = await Promise.all([
|
|
this.byUsername(username, projectId),
|
|
!!email ? this.byEmail(email, projectId) : undefined,
|
|
]);
|
|
if (!existingUsername || !existingEmail) throw UserErrors.ConflictIdentityTaken;
|
|
const userData = { projectId, username, email, hash, rolePolicyId };
|
|
return this.pg.user.create({ data: userData, include: { rolePolicy: true } });
|
|
}
|
|
|
|
async byIdentity(projectIdentity: string, identity: string) {
|
|
const username = identity.toLowerCase();
|
|
const email = identity.toLowerCase();
|
|
const OrUser = { OR: [{ username }, { email }] };
|
|
const OrProject = { project: { OR: [{ id: projectIdentity }, { slug: projectIdentity }] } };
|
|
const projectInclude = { include: { keyPairs: { where: { usage: KeyPairType.UserToken } } } };
|
|
const AND = [OrUser, OrProject];
|
|
return this.pg.user.findFirst({ where: { AND }, include: { rolePolicy: true, project: projectInclude } });
|
|
}
|
|
}
|