feat: allow users to have access to multiple oorgs
This commit is contained in:
@@ -53,7 +53,10 @@ export async function getUserAlerts(
|
||||
];
|
||||
|
||||
if (user.role == "client")
|
||||
filters.push({ recipientType: "team", recipientId: user.orgId });
|
||||
filters.push({
|
||||
recipientType: "team",
|
||||
recipientId: { $in: [...user.orgId] },
|
||||
});
|
||||
else filters.push({ recipientType: "team" });
|
||||
|
||||
const alerts = await alertsModel
|
||||
@@ -99,7 +102,10 @@ export async function markAllRead(user: AuthenticatedUser) {
|
||||
];
|
||||
|
||||
if (user.role == "client")
|
||||
filters.push({ recipientType: "team", recipientId: user.orgId });
|
||||
filters.push({
|
||||
recipientType: "team",
|
||||
recipientId: { $in: [...user.orgId] },
|
||||
});
|
||||
else filters.push({ recipientType: "team" });
|
||||
|
||||
const updatedResult = await alertsModel.updateMany(
|
||||
@@ -116,7 +122,10 @@ export async function getUnreadCount(user: AuthenticatedUser) {
|
||||
];
|
||||
|
||||
if (user.role == "client")
|
||||
filters.push({ recipientType: "team", recipientId: user.orgId });
|
||||
filters.push({
|
||||
recipientType: "team",
|
||||
recipientId: { $in: [...user.orgId] },
|
||||
});
|
||||
else filters.push({ recipientType: "team" });
|
||||
|
||||
const alerts = await alertsModel.find({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import bcrypt from 'bcryptjs';
|
||||
import bcrypt from "bcryptjs";
|
||||
import { FastifyReply, FastifyRequest } from "fastify";
|
||||
import { getToken } from "./tokens/token.service";
|
||||
import { Claim } from "./utils/claims";
|
||||
@@ -15,7 +15,7 @@ export type AuthenticatedUser = {
|
||||
sid?: string;
|
||||
type: string;
|
||||
userId?: string;
|
||||
orgId?: string;
|
||||
orgId?: Array<string>;
|
||||
role?: string;
|
||||
tenantId: string;
|
||||
claims: Array<Claim>;
|
||||
|
||||
@@ -35,7 +35,7 @@ export async function getSession(
|
||||
sid: session.id,
|
||||
type: "user",
|
||||
userId: user.id,
|
||||
orgId: user.orgId ? user.orgId.toString() : null,
|
||||
orgId: user.orgId ? user.orgId.map((item) => item.toString()) : [],
|
||||
role: user.role,
|
||||
tenantId: user.tenantId,
|
||||
claims: rules[user.role].claims ?? [],
|
||||
|
||||
@@ -58,6 +58,7 @@ const createTaskInput = z.object({
|
||||
})
|
||||
.optional(),
|
||||
note: z.string().optional(),
|
||||
orgId: z.string().optional(),
|
||||
});
|
||||
|
||||
const updateTaskInput = z.object({
|
||||
@@ -80,6 +81,7 @@ const updateTaskInput = z.object({
|
||||
currentStage: z.number(),
|
||||
})
|
||||
.optional(),
|
||||
orgId: z.string().optional(),
|
||||
});
|
||||
|
||||
const uploadTaskInput = z.object({
|
||||
|
||||
@@ -10,6 +10,8 @@ import {
|
||||
UpdateTaskInput,
|
||||
} from "./ctask.schema";
|
||||
|
||||
const InvalidOrg = new Error("invalid orgId");
|
||||
|
||||
export async function createTask(
|
||||
input: CreateTaskInput,
|
||||
user: AuthenticatedUser
|
||||
@@ -21,10 +23,14 @@ export async function createTask(
|
||||
};
|
||||
}
|
||||
|
||||
if (input.orgId && !user.orgId.includes(input.orgId)) {
|
||||
throw InvalidOrg;
|
||||
}
|
||||
|
||||
const task = await taskModel.create({
|
||||
...input,
|
||||
tenantId: user.tenantId,
|
||||
orgId: user.orgId,
|
||||
orgId: input.orgId ?? user.orgId[0],
|
||||
pid: generateId(),
|
||||
createdAt: new Date(),
|
||||
createdBy: user.userId ?? null,
|
||||
@@ -52,9 +58,13 @@ export async function updateTask(
|
||||
input: UpdateTaskInput,
|
||||
user: AuthenticatedUser
|
||||
) {
|
||||
if (input.orgId && !user.orgId.includes(input.orgId)) {
|
||||
throw InvalidOrg;
|
||||
}
|
||||
|
||||
const updatedTask = await taskModel
|
||||
.findOneAndUpdate(
|
||||
{ tenantId: user.tenantId, orgId: user.orgId, pid: taskId },
|
||||
{ tenantId: user.tenantId, orgId: { $in: user.orgId }, pid: taskId },
|
||||
input,
|
||||
{ new: true }
|
||||
)
|
||||
@@ -66,7 +76,11 @@ export async function updateTask(
|
||||
|
||||
export async function getTask(taskId: string, user: AuthenticatedUser) {
|
||||
return await taskModel
|
||||
.findOne({ tenantId: user.tenantId, orgId: user.orgId, pid: taskId })
|
||||
.findOne({
|
||||
tenantId: user.tenantId,
|
||||
orgId: { $in: user.orgId },
|
||||
pid: taskId,
|
||||
})
|
||||
.populate({ path: "createdBy", select: "pid name avatar" })
|
||||
.populate({ path: "assignedTo", select: "pid name avatar" });
|
||||
}
|
||||
@@ -118,7 +132,7 @@ export async function listTasks(
|
||||
$match: {
|
||||
$and: [
|
||||
{ tenantId: user.tenantId },
|
||||
{ orgId: user.orgId },
|
||||
{ orgId: { $in: user.orgId } },
|
||||
...filterObj,
|
||||
],
|
||||
},
|
||||
@@ -204,7 +218,7 @@ export async function listTasks(
|
||||
export async function deleteTask(taskId: string, user: AuthenticatedUser) {
|
||||
return await taskModel.deleteOne({
|
||||
pid: taskId,
|
||||
orgId: user.orgId,
|
||||
orgId: { $in: user.orgId },
|
||||
tenantId: user.tenantId,
|
||||
});
|
||||
}
|
||||
@@ -225,7 +239,7 @@ export async function searchTasks(
|
||||
$match: {
|
||||
$and: [
|
||||
{ tenantId: user.tenantId },
|
||||
{ orgId: user.orgId },
|
||||
{ orgId: { $in: user.orgId } },
|
||||
...filterObj,
|
||||
],
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ export async function createEvent(event: ChangeEvent) {
|
||||
export async function getEvents(user: AuthenticatedUser, from?: Date) {
|
||||
const filter: any[] = [{ tenantId: user.tenantId }];
|
||||
|
||||
if (user.role == "client") filter.push({ orgId: user.orgId });
|
||||
if (user.role == "client") filter.push({ orgId: { $in: user.orgId } });
|
||||
if (from) filter.push({ createdAt: { $gt: from } });
|
||||
|
||||
return await eventsModel.find({ $and: filter }).sort({ createdAt: -1 });
|
||||
|
||||
@@ -152,7 +152,11 @@ export async function listNotifications(
|
||||
});
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
|
||||
filterObj.push({
|
||||
client: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
|
||||
|
||||
@@ -51,7 +51,11 @@ export async function listOrgs(
|
||||
filterObj.push({
|
||||
$or: [
|
||||
{ type: "county" },
|
||||
{ _id: new mongoose.Types.ObjectId(user.orgId) },
|
||||
{
|
||||
_id: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
@@ -148,7 +152,11 @@ export async function searchOrgs(
|
||||
filterObj.push({
|
||||
$or: [
|
||||
{ type: "county" },
|
||||
{ _id: new mongoose.Types.ObjectId(user.orgId) },
|
||||
{
|
||||
_id: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,10 @@ export async function getPayment(paymentId: string, user: AuthenticatedUser) {
|
||||
pid: paymentId,
|
||||
});
|
||||
|
||||
if (user.role === "client" && paymentObj.client.toString() !== user.orgId)
|
||||
if (
|
||||
user.role === "client" &&
|
||||
!user.orgId.includes(paymentObj.client.toString())
|
||||
)
|
||||
return null;
|
||||
|
||||
return paymentObj;
|
||||
@@ -31,7 +34,11 @@ export async function listPayments(
|
||||
const filterObj = getFilterObject(params) || [];
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
|
||||
filterObj.push({
|
||||
client: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const pipeline: Array<any> = [
|
||||
|
||||
@@ -108,7 +108,11 @@ export async function getPermit(permitId: string, user: AuthenticatedUser) {
|
||||
.populate({ path: "assignedTo", select: "pid name avatar" })
|
||||
.populate({ path: "createdBy", select: "pid name avatar" });
|
||||
|
||||
if (permit && user.role == "client" && user.orgId != permit.client.toString())
|
||||
if (
|
||||
permit &&
|
||||
user.role == "client" &&
|
||||
!user.orgId.includes(permit.client.toString())
|
||||
)
|
||||
return null;
|
||||
|
||||
return permit;
|
||||
@@ -124,7 +128,11 @@ export async function listPermits(
|
||||
let filterObj = getFilterObject(params) || [];
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
|
||||
filterObj.push({
|
||||
client: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
|
||||
@@ -395,7 +403,11 @@ export async function searchPermit(
|
||||
const filterObj = getFilterObject(params) || [];
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
|
||||
filterObj.push({
|
||||
client: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (!params.searchToken)
|
||||
|
||||
@@ -28,7 +28,11 @@ export async function getProcessedPermit(
|
||||
.populate({ path: "assignedTo", select: "pid name avatar" })
|
||||
.populate({ path: "createdBy", select: "pid name avatar" });
|
||||
|
||||
if (permit && user.role == "client" && user.orgId != permit.client.toString())
|
||||
if (
|
||||
permit &&
|
||||
user.role == "client" &&
|
||||
!user.orgId.includes(permit.client.toString())
|
||||
)
|
||||
return null;
|
||||
|
||||
return permit;
|
||||
@@ -138,7 +142,11 @@ export async function listProcessedPermits(
|
||||
let filterObj = getFilterObject(params) || [];
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
|
||||
filterObj.push({
|
||||
client: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
|
||||
|
||||
@@ -35,7 +35,7 @@ export async function realTimeRoutes(fastify: FastifyInstance) {
|
||||
|
||||
if (
|
||||
req.user.role == "client" &&
|
||||
event.document.recipientId == req.user.orgId
|
||||
req.user.orgId.includes(event.document.recipientId)
|
||||
)
|
||||
alertFlag = true;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ export async function createRts(
|
||||
let defaultClient = input.client;
|
||||
const userInDb = await getUserWithoutPopulate(user.userId);
|
||||
if (userInDb && userInDb.orgId) {
|
||||
defaultClient = userInDb.orgId.toString();
|
||||
defaultClient = userInDb.orgId[0].toString();
|
||||
}
|
||||
|
||||
if (!input.stage) {
|
||||
@@ -83,7 +83,11 @@ export async function listRts(
|
||||
let filterObj = getFilterObject(params) || [];
|
||||
|
||||
if (user.role === "client") {
|
||||
filterObj.push({ client: new mongoose.Types.ObjectId(user.orgId) });
|
||||
filterObj.push({
|
||||
client: {
|
||||
$in: user.orgId.map((item) => new mongoose.Types.ObjectId(item)),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let { taggedFilter, taggedUserFilterIndex } = getTaggedUsersFilter(
|
||||
|
||||
@@ -53,7 +53,7 @@ export async function getUniqueFields(
|
||||
matchedValues = await orgModel.find().where("_id").in(values).exec();
|
||||
} else if (field === "client") {
|
||||
if (user.role == "client") {
|
||||
values = [user.orgId];
|
||||
values = user.orgId;
|
||||
}
|
||||
|
||||
matchedValues = await orgModel.find().where("_id").in(values).exec();
|
||||
|
||||
@@ -76,7 +76,10 @@ export async function getUserHandler(req: FastifyRequest, res: FastifyReply) {
|
||||
if (user == null)
|
||||
return res.code(404).send({ error: "resource not found" });
|
||||
|
||||
if (req.user.role == "client" && user.orgId.toString() != req.user.orgId)
|
||||
if (
|
||||
req.user.role == "client" &&
|
||||
!req.user.orgId.includes(user.orgId.toString())
|
||||
)
|
||||
return res.code(404).send({ error: "resource not found" });
|
||||
|
||||
return res.code(200).send(user);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { buildJsonSchemas } from "fastify-zod";
|
||||
import mongoose, { InferSchemaType } from "mongoose";
|
||||
import mongoose, { InferSchemaType, Schema } from "mongoose";
|
||||
import { z } from "zod";
|
||||
import { roles } from "../utils/roles";
|
||||
|
||||
@@ -13,7 +13,7 @@ const userSchema = new mongoose.Schema({
|
||||
unique: true,
|
||||
required: true,
|
||||
},
|
||||
orgId: { type: mongoose.Types.ObjectId, ref: "organization" },
|
||||
orgId: { type: [Schema.Types.ObjectId], ref: "organization" },
|
||||
firstName: String,
|
||||
lastName: String,
|
||||
name: String,
|
||||
@@ -73,7 +73,7 @@ const userCore = {
|
||||
.email(),
|
||||
avatar: z.string().optional(),
|
||||
role: z.enum(roles),
|
||||
orgId: z.string().optional(),
|
||||
orgId: z.array(z.string()).optional(),
|
||||
password: z.string().optional(),
|
||||
};
|
||||
|
||||
@@ -98,18 +98,20 @@ const updateUserInput = z.object({
|
||||
.optional(),
|
||||
avatar: z.string().url().optional(),
|
||||
role: z.enum(roles).optional(),
|
||||
orgId: z.string().optional(),
|
||||
orgId: z.array(z.string()).optional(),
|
||||
});
|
||||
|
||||
const userResponse = z.object({
|
||||
_id: z.string(),
|
||||
pid: z.string(),
|
||||
orgId: z
|
||||
.object({
|
||||
_id: z.string().optional(),
|
||||
pid: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
})
|
||||
.array(
|
||||
z.object({
|
||||
_id: z.string().optional(),
|
||||
pid: z.string().optional(),
|
||||
name: z.string().optional(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
firstName: z.string().optional(),
|
||||
lastName: z.string().optional(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import mongoose from 'mongoose';
|
||||
import { FastifyReply, FastifyRequest } from "fastify";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
export function errorHandler(
|
||||
error: any,
|
||||
@@ -12,7 +12,7 @@ export function errorHandler(
|
||||
|
||||
if (error.validation) {
|
||||
const errMsg = {
|
||||
type: 'validation_error',
|
||||
type: "validation_error",
|
||||
path: error.validation[0].instancePath,
|
||||
context: error.validationContext,
|
||||
msg: error.validation[0].message,
|
||||
@@ -25,13 +25,13 @@ export function errorHandler(
|
||||
if (error instanceof mongoose.mongo.MongoServerError) {
|
||||
if (error.code === 11000) {
|
||||
return res.code(400).send({
|
||||
type: 'duplicate_key',
|
||||
context: 'body',
|
||||
msg: 'value already exists',
|
||||
type: "duplicate_key",
|
||||
context: "body",
|
||||
msg: "value already exists",
|
||||
params: error.keyValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return res.code(500).send();
|
||||
return res.code(500).send(error.message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user