import mongoose from "mongoose"; import { generateId, generateToken } from "../utils/id"; import { CreateUserInput, UpdateUserInput, userModel } from "./user.schema"; import { sendMail } from "../utils/mail"; import { AuthenticatedUser } from "../auth"; import { createUserConfig } from "../userConfig/userConfig.service"; export const ErrUserNotFound = new Error("user not found"); export const ErrOpNotValid = new Error("operation is not valid"); export const ErrMissingOrdId = new Error( "orgId is required when role is client" ); export async function createUser( input: CreateUserInput, user: AuthenticatedUser ) { if ( input.role === "superAdmin" || (input.role == "admin" && user.role != "superAdmin") ) { throw ErrOpNotValid; } if (input.role == "client" && !input.orgId) { throw ErrMissingOrdId; } const token = await generateToken(); const newUser = await userModel.create({ tenantId: user.tenantId, pid: generateId(), name: input.firstName + " " + input.lastName, createdAt: new Date(), createdBy: user.userId, token: { value: token, expiry: new Date(Date.now() + 3600 * 48 * 1000), }, status: "invited", ...input, }); await createUserConfig(newUser.id, newUser.tenantId); const sent = await sendMail( input.email, "You have been invited to Quicker Permtis.", `Click here to register.
The above link expires in 48 hours
` ); return userModel .findOne({ pid: newUser.pid }) .populate({ path: "orgId", select: "pid name avatar" }); } export async function resetUser(userId: string, user: AuthenticatedUser) { if (user.role !== "superAdmin") { throw ErrOpNotValid; } const token = await generateToken(); const userInDb = await userModel.findOneAndUpdate( { pid: userId, tenantId: user.tenantId }, { $set: { token: { value: token, expiry: new Date(Date.now() + 3600 * 48 * 1000), }, }, }, { new: true } ); if (!userInDb) { throw ErrUserNotFound; } const sent = await sendMail( userInDb.email, "Quicker Permits account reset", `Click here to reset.
The above link expires in 48 hours
` ); } export async function getUser(userId: string) { if (mongoose.Types.ObjectId.isValid(userId)) { return await userModel .findById(userId) .populate({ path: "orgId", select: "_id pid name" }); } return await userModel .findOne({ $and: [{ pid: userId }], }) .populate({ path: "orgId", select: "_id pid name" }); } export async function getUserWithoutPopulate(userId: string) { return await userModel.findById(userId); } export async function getUserByToken(token: string) { return await userModel.findOne({ "token.value": token }); } export async function getUserByEmail(email: string) { return await userModel.findOne({ email: email }); } export async function listUsers(user: AuthenticatedUser) { if (user.role === "client") { return await userModel .find({ $and: [ { tenantId: user.tenantId }, { $or: [ { orgId: user.orgId, role: "client" }, { role: { $in: ["admin", "team", "superAdmin"] } }, ], }, { dev: { $ne: true } }, ], }) .select( "_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin" ) .populate({ path: "orgId", select: "_id pid name avatar" }) .populate({ path: "createdBy", select: "_id pid name avatar" }); } return await userModel .find({ $and: [{ tenantId: user.tenantId }, { dev: { $ne: true } }] }) .select( "_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin" ) .populate({ path: "orgId", select: "_id pid name avatar" }) .populate({ path: "createdBy", select: "_id pid name avatar" }); } export async function updateUser( userId: string, input: UpdateUserInput, user: AuthenticatedUser ) { if ( input.role === "superAdmin" || (input.role == "admin" && user.role != "superAdmin") ) { throw ErrOpNotValid; } return await userModel .findOneAndUpdate({ pid: userId }, input, { new: true, }) .select( "_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin" ) .populate({ path: "orgId", select: "_id pid name avatar" }); } export async function updateUserInternal( userId: string, input: UpdateUserInput ) { return await userModel .findOneAndUpdate({ pid: userId }, input, { new: true, }) .select( "_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin" ); } export async function deleteUser(userId: string, tenantId: string) { return await userModel.deleteOne({ $and: [{ pid: userId }, { tenantId: tenantId }], }); }