196 lines
5.2 KiB
TypeScript
196 lines
5.2 KiB
TypeScript
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 <a href="${
|
|
process.env.SERVER_DOMAIN +
|
|
"/auth/webauthn/register?token=" +
|
|
token +
|
|
"&email=" +
|
|
newUser.email
|
|
}">here</a> to register.</p><p>The above link expires in 48 hours</p>`
|
|
);
|
|
|
|
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",
|
|
`<p>Click <a href="${
|
|
process.env.SERVER_DOMAIN +
|
|
"/auth/webauthn/register?token=" +
|
|
token +
|
|
"&email=" +
|
|
userInDb.email
|
|
}">here</a> to reset.</p><p>The above link expires in 48 hours</p>`
|
|
);
|
|
}
|
|
|
|
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 }],
|
|
});
|
|
}
|