added client role and related code
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import { getFilterObject, getSortObject, PageQueryParams } from '../pagination';
|
||||
import { ChangeEvent, dbEvents } from '../realtime';
|
||||
import { generateId } from '../utils/id';
|
||||
import { getFilterObject, getSortObject, PageQueryParams } from "../pagination";
|
||||
import { ChangeEvent, dbEvents } from "../realtime";
|
||||
import { generateId } from "../utils/id";
|
||||
import {
|
||||
CreateOrgInput,
|
||||
orgFields,
|
||||
orgModel,
|
||||
UpdateOrgInput,
|
||||
} from './organization.schema';
|
||||
} from "./organization.schema";
|
||||
|
||||
export async function createOrg(input: CreateOrgInput, tenantId: string) {
|
||||
const org = await orgModel.create({
|
||||
@@ -17,13 +17,13 @@ export async function createOrg(input: CreateOrgInput, tenantId: string) {
|
||||
});
|
||||
|
||||
dbEvents.emit(
|
||||
'change',
|
||||
"change",
|
||||
{
|
||||
type: 'insert',
|
||||
collection: 'orgs',
|
||||
type: "insert",
|
||||
collection: "orgs",
|
||||
document: org,
|
||||
} as ChangeEvent,
|
||||
['org:read']
|
||||
["org:read"]
|
||||
);
|
||||
|
||||
return org;
|
||||
@@ -45,7 +45,7 @@ export async function listOrgs(params: PageQueryParams, tenantId: string) {
|
||||
{ $match: { $and: [{ tenantId: tenantId }, { ...filterObj }] } },
|
||||
{
|
||||
$facet: {
|
||||
metadata: [{ $count: 'count' }],
|
||||
metadata: [{ $count: "count" }],
|
||||
data: [
|
||||
{ $sort: sortObj },
|
||||
{ $skip: (page - 1) * pageSize },
|
||||
@@ -83,13 +83,13 @@ export async function updateOrg(
|
||||
|
||||
if (updateOrgResult) {
|
||||
dbEvents.emit(
|
||||
'change',
|
||||
"change",
|
||||
{
|
||||
type: 'update',
|
||||
collection: 'orgs',
|
||||
type: "update",
|
||||
collection: "orgs",
|
||||
document: updateOrgResult,
|
||||
} as ChangeEvent,
|
||||
['org:read']
|
||||
["org:read"]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -103,15 +103,15 @@ export async function deleteOrg(orgId: string, tenantId: string) {
|
||||
|
||||
if (res.deletedCount > 0) {
|
||||
dbEvents.emit(
|
||||
'change',
|
||||
"change",
|
||||
{
|
||||
type: 'delete',
|
||||
collection: 'orgs',
|
||||
type: "delete",
|
||||
collection: "orgs",
|
||||
document: {
|
||||
pid: orgId,
|
||||
},
|
||||
} as ChangeEvent,
|
||||
['org:read']
|
||||
["org:read"]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ export async function searchOrgs(params: PageQueryParams, tenantId: string) {
|
||||
if (!params.searchToken)
|
||||
return { orgs: [], metadata: { count: 0, page, pageSize } };
|
||||
|
||||
const regex = new RegExp(params.searchToken, 'i');
|
||||
const regex = new RegExp(params.searchToken, "i");
|
||||
|
||||
const orgs = await orgModel.aggregate([
|
||||
{ $match: { $and: [{ tenantId: tenantId }, { ...filterObj }] } },
|
||||
@@ -138,7 +138,7 @@ export async function searchOrgs(params: PageQueryParams, tenantId: string) {
|
||||
},
|
||||
{
|
||||
$facet: {
|
||||
metadata: [{ $count: 'count' }],
|
||||
metadata: [{ $count: "count" }],
|
||||
data: [
|
||||
{ $sort: sortObj },
|
||||
{ $skip: (page - 1) * pageSize },
|
||||
|
||||
@@ -47,7 +47,7 @@ export async function listPermitsHandler(
|
||||
|
||||
try {
|
||||
const authUser = req.user;
|
||||
const orgList = await listPermits(queryParams, authUser.tenantId);
|
||||
const orgList = await listPermits(queryParams, authUser);
|
||||
return res.code(200).send(orgList);
|
||||
} catch (err) {
|
||||
return err;
|
||||
@@ -97,7 +97,7 @@ export async function searchPermitHandler(
|
||||
|
||||
try {
|
||||
const authUser = req.user;
|
||||
const permitList = await searchPermit(queryParams, authUser.tenantId);
|
||||
const permitList = await searchPermit(queryParams, authUser);
|
||||
return res.code(200).send(permitList);
|
||||
} catch (err) {
|
||||
return err;
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { orgModel } from '../organization/organization.schema';
|
||||
import { getFilterObject, getSortObject, PageQueryParams } from '../pagination';
|
||||
import { userModel } from '../user/user.schema';
|
||||
import { generateId } from '../utils/id';
|
||||
import { orgModel } from "../organization/organization.schema";
|
||||
import { getFilterObject, getSortObject, PageQueryParams } from "../pagination";
|
||||
import { userModel } from "../user/user.schema";
|
||||
import { generateId } from "../utils/id";
|
||||
import {
|
||||
CreatePermitInput,
|
||||
permitFields,
|
||||
permitModel,
|
||||
UpdatePermitInput,
|
||||
} from './permit.schema';
|
||||
import { ChangeEvent, dbEvents } from '../realtime';
|
||||
import { permitPipeline } from '../utils/pipeline';
|
||||
import { AuthenticatedUser } from '../auth';
|
||||
} from "./permit.schema";
|
||||
import { ChangeEvent, dbEvents } from "../realtime";
|
||||
import { permitPipeline } from "../utils/pipeline";
|
||||
import { AuthenticatedUser } from "../auth";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
export async function createPermit(
|
||||
input: CreatePermitInput,
|
||||
@@ -32,13 +33,13 @@ export async function createPermit(
|
||||
});
|
||||
|
||||
dbEvents.emit(
|
||||
'change',
|
||||
"change",
|
||||
{
|
||||
type: 'insert',
|
||||
collection: 'permits',
|
||||
type: "insert",
|
||||
collection: "permits",
|
||||
document: permit,
|
||||
} as ChangeEvent,
|
||||
['permit:read']
|
||||
["permit:read"]
|
||||
);
|
||||
|
||||
return permit;
|
||||
@@ -51,26 +52,33 @@ export async function getPermit(permitId: string, tenantId: string) {
|
||||
})
|
||||
//.populate({ path: "county", select: "pid name avatar" })
|
||||
//.populate({ path: "client", select: "pid name avatar" })
|
||||
.populate({ path: 'assignedTo', select: 'pid name avatar' })
|
||||
.populate({ path: 'createdBy', select: 'pid name avatar' });
|
||||
.populate({ path: "assignedTo", select: "pid name avatar" })
|
||||
.populate({ path: "createdBy", select: "pid name avatar" });
|
||||
}
|
||||
|
||||
export async function listPermits(params: PageQueryParams, tenantId: string) {
|
||||
export async function listPermits(
|
||||
params: PageQueryParams,
|
||||
user: AuthenticatedUser
|
||||
) {
|
||||
const page = params.page || 1;
|
||||
const pageSize = params.pageSize || 10;
|
||||
const sortObj = getSortObject(params, permitFields);
|
||||
const filterObj = getFilterObject(params);
|
||||
const filterObj = getFilterObject(params) || {};
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj["client"] = new mongoose.Types.ObjectId(user.orgId);
|
||||
}
|
||||
|
||||
const permitsList = await permitModel.aggregate([
|
||||
{
|
||||
$match: { $and: [{ tenantId: tenantId }, { ...filterObj }] },
|
||||
$match: { $and: [{ tenantId: user.tenantId }, { ...filterObj }] },
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: 'users',
|
||||
localField: 'assignedTo',
|
||||
foreignField: '_id',
|
||||
as: 'assignedRec',
|
||||
from: "users",
|
||||
localField: "assignedTo",
|
||||
foreignField: "_id",
|
||||
as: "assignedRec",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -112,12 +120,12 @@ export async function listPermits(params: PageQueryParams, tenantId: string) {
|
||||
statusUpdated: 1,
|
||||
assignedTo: {
|
||||
$let: {
|
||||
vars: { assigned: { $arrayElemAt: ['$assignedRec', 0] } },
|
||||
vars: { assigned: { $arrayElemAt: ["$assignedRec", 0] } },
|
||||
in: {
|
||||
_id: '$$assigned._id',
|
||||
pid: '$$assigned.pid',
|
||||
name: '$$assigned.name',
|
||||
avatar: '$$assigned.avatar',
|
||||
_id: "$$assigned._id",
|
||||
pid: "$$assigned.pid",
|
||||
name: "$$assigned.name",
|
||||
avatar: "$$assigned.avatar",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -125,7 +133,7 @@ export async function listPermits(params: PageQueryParams, tenantId: string) {
|
||||
},
|
||||
{
|
||||
$facet: {
|
||||
metadata: [{ $count: 'count' }],
|
||||
metadata: [{ $count: "count" }],
|
||||
data: [
|
||||
{ $sort: sortObj },
|
||||
{ $skip: (page - 1) * pageSize },
|
||||
@@ -161,20 +169,20 @@ export async function updatePermit(
|
||||
{ ...input, lastUpdateDate: new Date() },
|
||||
{ new: true }
|
||||
)
|
||||
.populate({ path: 'county', select: 'pid name avatar' })
|
||||
.populate({ path: 'client', select: 'pid name avatar' })
|
||||
.populate({ path: 'assignedTo', select: 'pid name avatar' })
|
||||
.populate({ path: 'createdBy', select: 'pid name avatar' });
|
||||
.populate({ path: "county", select: "pid name avatar" })
|
||||
.populate({ path: "client", select: "pid name avatar" })
|
||||
.populate({ path: "assignedTo", select: "pid name avatar" })
|
||||
.populate({ path: "createdBy", select: "pid name avatar" });
|
||||
|
||||
if (updatePermitResult) {
|
||||
dbEvents.emit(
|
||||
'change',
|
||||
"change",
|
||||
{
|
||||
type: 'update',
|
||||
collection: 'permits',
|
||||
type: "update",
|
||||
collection: "permits",
|
||||
document: updatePermitResult,
|
||||
} as ChangeEvent,
|
||||
['permit:read']
|
||||
["permit:read"]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -187,50 +195,57 @@ export async function deletePermit(permitId: string, tenantId: string) {
|
||||
});
|
||||
|
||||
dbEvents.emit(
|
||||
'change',
|
||||
"change",
|
||||
{
|
||||
type: 'delete',
|
||||
collection: 'permits',
|
||||
type: "delete",
|
||||
collection: "permits",
|
||||
document: {
|
||||
pid: permitId,
|
||||
},
|
||||
} as ChangeEvent,
|
||||
['permit:read']
|
||||
["permit:read"]
|
||||
);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export async function searchPermit(params: PageQueryParams, tenantId: string) {
|
||||
export async function searchPermit(
|
||||
params: PageQueryParams,
|
||||
user: AuthenticatedUser
|
||||
) {
|
||||
const page = params.page || 1;
|
||||
const pageSize = params.pageSize || 10;
|
||||
const sortObj = getSortObject(params, permitFields);
|
||||
const filterObj = getFilterObject(params);
|
||||
const filterObj = getFilterObject(params) || {};
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj["client"] = new mongoose.Types.ObjectId(user.orgId);
|
||||
}
|
||||
|
||||
if (!params.searchToken)
|
||||
return { permits: [], metadata: { count: 0, page, pageSize } };
|
||||
|
||||
const regex = new RegExp(params.searchToken, 'i');
|
||||
const regex = new RegExp(params.searchToken, "i");
|
||||
|
||||
const permitsList = await permitModel.aggregate([
|
||||
{
|
||||
$match: { $and: [{ tenantId: tenantId }, { ...filterObj }] },
|
||||
$match: { $and: [{ tenantId: user.tenantId }, { ...filterObj }] },
|
||||
},
|
||||
{
|
||||
$match: {
|
||||
$or: [
|
||||
{ permitNumber: { $regex: regex } },
|
||||
{ link: { $regex: regex } },
|
||||
{ 'address.full_address': { $regex: regex } },
|
||||
{ "address.full_address": { $regex: regex } },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
$lookup: {
|
||||
from: 'users',
|
||||
localField: 'assignedTo',
|
||||
foreignField: '_id',
|
||||
as: 'assignedRec',
|
||||
from: "users",
|
||||
localField: "assignedTo",
|
||||
foreignField: "_id",
|
||||
as: "assignedRec",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -272,12 +287,12 @@ export async function searchPermit(params: PageQueryParams, tenantId: string) {
|
||||
statusUpdated: 1,
|
||||
assignedTo: {
|
||||
$let: {
|
||||
vars: { assigned: { $arrayElemAt: ['$assignedRec', 0] } },
|
||||
vars: { assigned: { $arrayElemAt: ["$assignedRec", 0] } },
|
||||
in: {
|
||||
_id: '$$assigned._id',
|
||||
pid: '$$assigned.pid',
|
||||
name: '$$assigned.name',
|
||||
avatar: '$$assigned.avatar',
|
||||
_id: "$$assigned._id",
|
||||
pid: "$$assigned.pid",
|
||||
name: "$$assigned.name",
|
||||
avatar: "$$assigned.avatar",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -285,7 +300,7 @@ export async function searchPermit(params: PageQueryParams, tenantId: string) {
|
||||
},
|
||||
{
|
||||
$facet: {
|
||||
metadata: [{ $count: 'count' }],
|
||||
metadata: [{ $count: "count" }],
|
||||
data: [
|
||||
{ $sort: sortObj },
|
||||
{ $skip: (page - 1) * pageSize },
|
||||
@@ -312,12 +327,12 @@ export async function getUniqueValuesPermit(field: string, tenenatId: string) {
|
||||
let values = await permitModel.distinct(field, { tenantId: tenenatId });
|
||||
|
||||
let matchedValues = [];
|
||||
if (field === 'county.name') {
|
||||
matchedValues = await orgModel.find().where('name').in(values).exec();
|
||||
} else if (field === 'client') {
|
||||
matchedValues = await orgModel.find().where('_id').in(values).exec();
|
||||
} else if (field === 'assignedTo') {
|
||||
matchedValues = await userModel.find().where('name').in(values).exec();
|
||||
if (field === "county.name") {
|
||||
matchedValues = await orgModel.find().where("name").in(values).exec();
|
||||
} else if (field === "client") {
|
||||
matchedValues = await orgModel.find().where("_id").in(values).exec();
|
||||
} else if (field === "assignedTo") {
|
||||
matchedValues = await userModel.find().where("name").in(values).exec();
|
||||
}
|
||||
|
||||
if (matchedValues.length > 0) {
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { PageQueryParams } from '../pagination';
|
||||
import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
|
||||
import { PageQueryParams } from "../pagination";
|
||||
import {
|
||||
getProcessedPermit,
|
||||
getUniqueValuesProcessed,
|
||||
listProcessedPermits,
|
||||
updateProcessed,
|
||||
} from './processed.service';
|
||||
import { $processed, UpdateProcessedInput } from './processed.schema';
|
||||
import { noteRoutes } from '../note/note.route';
|
||||
} from "./processed.service";
|
||||
import { $processed, UpdateProcessedInput } from "./processed.schema";
|
||||
import { noteRoutes } from "../note/note.route";
|
||||
|
||||
export async function processedRoutes(fastify: FastifyInstance) {
|
||||
fastify.get(
|
||||
'/',
|
||||
"/",
|
||||
{
|
||||
schema: {
|
||||
querystring: $processed('pageQueryParams'),
|
||||
querystring: $processed("pageQueryParams"),
|
||||
},
|
||||
config: { requiredClaims: ['permit:read'] },
|
||||
config: { requiredClaims: ["permit:read"] },
|
||||
preHandler: [fastify.authorize],
|
||||
},
|
||||
async (req: FastifyRequest, res: FastifyReply) => {
|
||||
const params = req.query as PageQueryParams;
|
||||
|
||||
try {
|
||||
const permits = await listProcessedPermits(params, req.user.tenantId);
|
||||
const permits = await listProcessedPermits(params, req.user);
|
||||
return res.code(200).send(permits);
|
||||
} catch (err) {
|
||||
return err;
|
||||
@@ -32,19 +32,19 @@ export async function processedRoutes(fastify: FastifyInstance) {
|
||||
);
|
||||
|
||||
fastify.get(
|
||||
'/search',
|
||||
"/search",
|
||||
{
|
||||
schema: {
|
||||
querystring: $processed('pageQueryParams'),
|
||||
querystring: $processed("pageQueryParams"),
|
||||
},
|
||||
config: { requiredClaims: ['permit:read'] },
|
||||
config: { requiredClaims: ["permit:read"] },
|
||||
preHandler: [fastify.authorize],
|
||||
},
|
||||
async (req: FastifyRequest, res: FastifyReply) => {
|
||||
const params = req.query as PageQueryParams;
|
||||
|
||||
try {
|
||||
const permits = await listProcessedPermits(params, req.user.tenantId);
|
||||
const permits = await listProcessedPermits(params, req.user);
|
||||
return res.code(200).send(permits);
|
||||
} catch (err) {
|
||||
return err;
|
||||
@@ -53,15 +53,15 @@ export async function processedRoutes(fastify: FastifyInstance) {
|
||||
);
|
||||
|
||||
fastify.get(
|
||||
'/:permitId',
|
||||
"/:permitId",
|
||||
{
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: { permitId: { type: 'string' } },
|
||||
type: "object",
|
||||
properties: { permitId: { type: "string" } },
|
||||
},
|
||||
},
|
||||
config: { requiredClaims: ['permit:read'] },
|
||||
config: { requiredClaims: ["permit:read"] },
|
||||
preHandler: [fastify.authorize],
|
||||
},
|
||||
async (req: FastifyRequest, res: FastifyReply) => {
|
||||
@@ -77,16 +77,16 @@ export async function processedRoutes(fastify: FastifyInstance) {
|
||||
);
|
||||
|
||||
fastify.patch(
|
||||
'/:permitId',
|
||||
"/:permitId",
|
||||
{
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: { permitId: { type: 'string' } },
|
||||
type: "object",
|
||||
properties: { permitId: { type: "string" } },
|
||||
},
|
||||
body: $processed('updateProcessedInput'),
|
||||
body: $processed("updateProcessedInput"),
|
||||
},
|
||||
config: { requiredClaims: ['permit:write'] },
|
||||
config: { requiredClaims: ["permit:write"] },
|
||||
preHandler: [fastify.authorize],
|
||||
},
|
||||
async (req: FastifyRequest, res: FastifyReply) => {
|
||||
@@ -103,17 +103,17 @@ export async function processedRoutes(fastify: FastifyInstance) {
|
||||
);
|
||||
|
||||
fastify.get(
|
||||
'/fields/:field',
|
||||
"/fields/:field",
|
||||
{
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
type: "object",
|
||||
properties: {
|
||||
field: { type: 'string' },
|
||||
field: { type: "string" },
|
||||
},
|
||||
},
|
||||
},
|
||||
config: { requiredClaims: ['permit:read'] },
|
||||
config: { requiredClaims: ["permit:read"] },
|
||||
preHandler: [fastify.authorize],
|
||||
},
|
||||
async (req: FastifyRequest, res: FastifyReply) => {
|
||||
@@ -132,8 +132,8 @@ export async function processedRoutes(fastify: FastifyInstance) {
|
||||
);
|
||||
|
||||
await noteRoutes(fastify, {
|
||||
read: 'permit:read',
|
||||
write: 'permit:write',
|
||||
delete: 'permit:delete',
|
||||
read: "permit:read",
|
||||
write: "permit:write",
|
||||
delete: "permit:delete",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { AuthenticatedUser } from '../auth';
|
||||
import { orgModel } from '../organization/organization.schema';
|
||||
import { getFilterObject, getSortObject, PageQueryParams } from '../pagination';
|
||||
import { userModel } from '../user/user.schema';
|
||||
import mongoose from "mongoose";
|
||||
import { AuthenticatedUser } from "../auth";
|
||||
import { orgModel } from "../organization/organization.schema";
|
||||
import { getFilterObject, getSortObject, PageQueryParams } from "../pagination";
|
||||
import { userModel } from "../user/user.schema";
|
||||
import {
|
||||
processedFields,
|
||||
processedModel,
|
||||
UpdateProcessedInput,
|
||||
} from './processed.schema';
|
||||
} from "./processed.schema";
|
||||
|
||||
export async function getProcessedPermit(permitId: String, tenantId: String) {
|
||||
return await processedModel.findOne({
|
||||
@@ -27,35 +28,39 @@ export async function updateProcessed(
|
||||
{ ...input, lastUpdateDate: new Date() },
|
||||
{ new: true }
|
||||
)
|
||||
.populate({ path: 'county', select: 'pid name avatar' })
|
||||
.populate({ path: 'client', select: 'pid name avatar' })
|
||||
.populate({ path: 'assignedTo', select: 'pid name avatar' })
|
||||
.populate({ path: 'createdBy', select: 'pid name avatar' });
|
||||
.populate({ path: "county", select: "pid name avatar" })
|
||||
.populate({ path: "client", select: "pid name avatar" })
|
||||
.populate({ path: "assignedTo", select: "pid name avatar" })
|
||||
.populate({ path: "createdBy", select: "pid name avatar" });
|
||||
}
|
||||
|
||||
export async function listProcessedPermits(
|
||||
params: PageQueryParams,
|
||||
tenantId: string
|
||||
user: AuthenticatedUser
|
||||
) {
|
||||
const page = params.page || 1;
|
||||
const pageSize = params.pageSize || 10;
|
||||
const sortObj = getSortObject(params, processedFields);
|
||||
const filterObj = getFilterObject(params);
|
||||
const filterObj = getFilterObject(params) || {};
|
||||
|
||||
if (user.role == "client") {
|
||||
filterObj["client"] = new mongoose.Types.ObjectId(user.orgId);
|
||||
}
|
||||
|
||||
const pipeline: any = [
|
||||
{
|
||||
$match: { $and: [{ tenantId: tenantId }, { ...filterObj }] },
|
||||
$match: { $and: [{ tenantId: user.tenantId }, { ...filterObj }] },
|
||||
},
|
||||
];
|
||||
|
||||
if (params.searchToken && params.searchToken != '') {
|
||||
const regex = new RegExp(params.searchToken, 'i');
|
||||
if (params.searchToken && params.searchToken != "") {
|
||||
const regex = new RegExp(params.searchToken, "i");
|
||||
pipeline.push({
|
||||
$match: {
|
||||
$or: [
|
||||
{ permitNumber: { $regex: regex } },
|
||||
{ link: { $regex: regex } },
|
||||
{ 'address.full_address': { $regex: regex } },
|
||||
{ "address.full_address": { $regex: regex } },
|
||||
],
|
||||
},
|
||||
});
|
||||
@@ -65,10 +70,10 @@ export async function listProcessedPermits(
|
||||
...[
|
||||
{
|
||||
$lookup: {
|
||||
from: 'users',
|
||||
localField: 'assignedTo',
|
||||
foreignField: '_id',
|
||||
as: 'assignedRec',
|
||||
from: "users",
|
||||
localField: "assignedTo",
|
||||
foreignField: "_id",
|
||||
as: "assignedRec",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -111,12 +116,12 @@ export async function listProcessedPermits(
|
||||
transferDate: 1,
|
||||
assignedTo: {
|
||||
$let: {
|
||||
vars: { assigned: { $arrayElemAt: ['$assignedRec', 0] } },
|
||||
vars: { assigned: { $arrayElemAt: ["$assignedRec", 0] } },
|
||||
in: {
|
||||
_id: '$$assigned._id',
|
||||
pid: '$$assigned.pid',
|
||||
name: '$$assigned.name',
|
||||
avatar: '$$assigned.avatar',
|
||||
_id: "$$assigned._id",
|
||||
pid: "$$assigned.pid",
|
||||
name: "$$assigned.name",
|
||||
avatar: "$$assigned.avatar",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -124,7 +129,7 @@ export async function listProcessedPermits(
|
||||
},
|
||||
{
|
||||
$facet: {
|
||||
metadata: [{ $count: 'count' }],
|
||||
metadata: [{ $count: "count" }],
|
||||
data: [
|
||||
{ $sort: sortObj },
|
||||
{ $skip: (page - 1) * pageSize },
|
||||
@@ -157,12 +162,12 @@ export async function getUniqueValuesProcessed(
|
||||
let values = await processedModel.distinct(field, { tenantId: tenenatId });
|
||||
|
||||
let matchedValues = [];
|
||||
if (field === 'county.name') {
|
||||
matchedValues = await orgModel.find().where('name').in(values).exec();
|
||||
} else if (field === 'client') {
|
||||
matchedValues = await orgModel.find().where('_id').in(values).exec();
|
||||
} else if (field === 'assignedTo') {
|
||||
matchedValues = await userModel.find().where('name').in(values).exec();
|
||||
if (field === "county.name") {
|
||||
matchedValues = await orgModel.find().where("name").in(values).exec();
|
||||
} else if (field === "client") {
|
||||
matchedValues = await orgModel.find().where("_id").in(values).exec();
|
||||
} else if (field === "assignedTo") {
|
||||
matchedValues = await userModel.find().where("name").in(values).exec();
|
||||
}
|
||||
|
||||
if (matchedValues.length > 0) {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { FastifyReply, FastifyRequest } from 'fastify';
|
||||
import { FastifyReply, FastifyRequest } from "fastify";
|
||||
import {
|
||||
createUser,
|
||||
deleteUser,
|
||||
ErrMissingOrdId,
|
||||
ErrOpNotValid,
|
||||
getUser,
|
||||
listUsers,
|
||||
updateUser,
|
||||
} from './user.service';
|
||||
import { CreateUserInput, UpdateUserInput } from './user.schema';
|
||||
} from "./user.service";
|
||||
import { CreateUserInput, UpdateUserInput } from "./user.schema";
|
||||
|
||||
export async function createUserHandler(
|
||||
req: FastifyRequest,
|
||||
@@ -19,8 +20,12 @@ export async function createUserHandler(
|
||||
const user = await createUser(body, req.user);
|
||||
return res.code(201).send(user);
|
||||
} catch (err) {
|
||||
if (err instanceof Error && err.message == ErrOpNotValid.message)
|
||||
return res.code(400).send(err.message);
|
||||
if (
|
||||
err instanceof Error &&
|
||||
(err.message == ErrOpNotValid.message ||
|
||||
err.message == ErrMissingOrdId.message)
|
||||
)
|
||||
return res.code(400).send({ error: err.message });
|
||||
return err;
|
||||
}
|
||||
}
|
||||
@@ -29,14 +34,14 @@ export async function getCurrentUserHandler(
|
||||
req: FastifyRequest,
|
||||
res: FastifyReply
|
||||
) {
|
||||
if (req.user.type !== 'user') {
|
||||
if (req.user.type !== "user") {
|
||||
return res.code(400).send();
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await getUser(req.user.userId);
|
||||
if (user == null)
|
||||
return res.code(404).send({ error: 'resource not found' });
|
||||
return res.code(404).send({ error: "resource not found" });
|
||||
|
||||
return res.code(200).send(user);
|
||||
} catch (err) {
|
||||
@@ -50,7 +55,7 @@ export async function getUserHandler(req: FastifyRequest, res: FastifyReply) {
|
||||
try {
|
||||
const user = await getUser(userId);
|
||||
if (user == null)
|
||||
return res.code(404).send({ error: 'resource not found' });
|
||||
return res.code(404).send({ error: "resource not found" });
|
||||
|
||||
return res.code(200).send(user);
|
||||
} catch (err) {
|
||||
@@ -76,7 +81,7 @@ export async function updateUserHandler(
|
||||
|
||||
try {
|
||||
const updatedUser = await updateUser(userId, input);
|
||||
if (!updateUser) return res.code(404).send({ error: 'resource not found' });
|
||||
if (!updateUser) return res.code(404).send({ error: "resource not found" });
|
||||
|
||||
return res.code(200).send(updatedUser);
|
||||
} catch (err) {
|
||||
@@ -93,7 +98,7 @@ export async function deleteUserHandler(
|
||||
try {
|
||||
const deleteResult = await deleteUser(userId, req.user.tenantId);
|
||||
if (deleteResult.deletedCount == 0)
|
||||
return res.code(404).send({ error: 'resource not found' });
|
||||
return res.code(404).send({ error: "resource not found" });
|
||||
|
||||
return res.code(204).send();
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { buildJsonSchemas } from 'fastify-zod';
|
||||
import mongoose, { InferSchemaType } from 'mongoose';
|
||||
import { z } from 'zod';
|
||||
import { roles } from '../utils/roles';
|
||||
import { buildJsonSchemas } from "fastify-zod";
|
||||
import mongoose, { InferSchemaType } from "mongoose";
|
||||
import { z } from "zod";
|
||||
import { roles } from "../utils/roles";
|
||||
|
||||
const userSchema = new mongoose.Schema({
|
||||
tenantId: {
|
||||
@@ -30,7 +30,7 @@ const userSchema = new mongoose.Schema({
|
||||
},
|
||||
defaultClient: {
|
||||
type: mongoose.Types.ObjectId,
|
||||
ref: 'organization',
|
||||
ref: "organization",
|
||||
},
|
||||
passKeys: [new mongoose.Schema({}, { _id: false, strict: false })],
|
||||
challenge: new mongoose.Schema(
|
||||
@@ -53,7 +53,7 @@ const userSchema = new mongoose.Schema({
|
||||
dev: Boolean,
|
||||
});
|
||||
|
||||
export const userModel = mongoose.model('user', userSchema);
|
||||
export const userModel = mongoose.model("user", userSchema);
|
||||
|
||||
export type User = InferSchemaType<typeof userSchema>;
|
||||
|
||||
@@ -62,8 +62,8 @@ const userCore = {
|
||||
lastName: z.string().max(30),
|
||||
email: z
|
||||
.string({
|
||||
required_error: 'Email is required',
|
||||
invalid_type_error: 'Email must be a valid string',
|
||||
required_error: "Email is required",
|
||||
invalid_type_error: "Email must be a valid string",
|
||||
})
|
||||
.email(),
|
||||
avatar: z.string().optional(),
|
||||
@@ -75,14 +75,9 @@ const createUserInput = z
|
||||
.object({
|
||||
...userCore,
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (data.role == 'builder' && !data.orgId) {
|
||||
ctx.addIssue({
|
||||
path: ['orgId'],
|
||||
message: 'orgId is required when role is "builder"',
|
||||
code: z.ZodIssueCode.custom,
|
||||
});
|
||||
}
|
||||
.refine((data) => data.role !== "client" || data.orgId, {
|
||||
message: 'orgId is required when role is "client"',
|
||||
path: ["orgId"],
|
||||
});
|
||||
|
||||
const updateUserInput = z.object({
|
||||
@@ -90,8 +85,8 @@ const updateUserInput = z.object({
|
||||
lastName: z.string().max(30).optional(),
|
||||
email: z
|
||||
.string({
|
||||
required_error: 'Email is required',
|
||||
invalid_type_error: 'Email must be a valid string',
|
||||
required_error: "Email is required",
|
||||
invalid_type_error: "Email must be a valid string",
|
||||
})
|
||||
.email()
|
||||
.optional(),
|
||||
@@ -125,5 +120,5 @@ export const { schemas: userSchemas, $ref: $user } = buildJsonSchemas(
|
||||
updateUserInput,
|
||||
userResponse,
|
||||
},
|
||||
{ $id: 'user' }
|
||||
{ $id: "user" }
|
||||
);
|
||||
|
||||
@@ -1,43 +1,50 @@
|
||||
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 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";
|
||||
|
||||
export const ErrOpNotValid = new Error('operation is not valid');
|
||||
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 == 'admin' && user.role != 'superAdmin') {
|
||||
if (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,
|
||||
name: input.firstName + " " + input.lastName,
|
||||
createdAt: new Date(),
|
||||
createdBy: user.userId,
|
||||
token: {
|
||||
value: token,
|
||||
expiry: new Date(Date.now() + 3600 * 48 * 1000),
|
||||
},
|
||||
status: 'invited',
|
||||
status: "invited",
|
||||
...input,
|
||||
});
|
||||
|
||||
const sent = await sendMail(
|
||||
input.email,
|
||||
'You have been invited to Quicker Permtis.',
|
||||
"You have been invited to Quicker Permtis.",
|
||||
`Click <a href="${
|
||||
process.env.SERVER_DOMAIN +
|
||||
'/auth/webauthn/register?token=' +
|
||||
"/auth/webauthn/register?token=" +
|
||||
token +
|
||||
'&email=' +
|
||||
"&email=" +
|
||||
newUser.email
|
||||
}">here</a> to register.`
|
||||
);
|
||||
@@ -56,7 +63,7 @@ export async function getUser(userId: string) {
|
||||
}
|
||||
|
||||
export async function getUserByToken(token: string) {
|
||||
return await userModel.findOne({ 'token.value': token });
|
||||
return await userModel.findOne({ "token.value": token });
|
||||
}
|
||||
|
||||
export async function getUserByEmail(email: string) {
|
||||
@@ -67,7 +74,7 @@ export async function listUsers(tenantId: string) {
|
||||
return await userModel
|
||||
.find({ $and: [{ tenantId: tenantId }, { dev: { $ne: true } }] })
|
||||
.select(
|
||||
'_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin'
|
||||
"_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -77,7 +84,7 @@ export async function updateUser(userId: string, input: UpdateUserInput) {
|
||||
new: true,
|
||||
})
|
||||
.select(
|
||||
'_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin'
|
||||
"_id pid orgId firstName lastName name email role avatar status createdAt createdBy lastLogin"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,23 @@ export const rules: Record<
|
||||
users: ["__v"],
|
||||
},
|
||||
},
|
||||
client: {
|
||||
claims: [
|
||||
"permit:read",
|
||||
"file:upload",
|
||||
"file:download",
|
||||
"view:read",
|
||||
"view:write",
|
||||
"view:delete",
|
||||
],
|
||||
hiddenFields: {
|
||||
orgs: ["__v"],
|
||||
permits: ["__v"],
|
||||
rts: ["__v"],
|
||||
tasks: ["__v"],
|
||||
users: ["__v"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const roles = Object.keys(rules) as [
|
||||
|
||||
Reference in New Issue
Block a user