add notes routes

This commit is contained in:
2025-02-07 18:39:55 +05:30
parent a130d0cb73
commit d043b5aed7
8 changed files with 312 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
import { FastifyReply, FastifyRequest } from "fastify";
import { createNote, deleteNote, listNotes, updateNote } from "./note.service";
import { CreateNoteInput } from "./note.schema";
export async function createNoteHandler(
req: FastifyRequest,
res: FastifyReply
) {
const { resourceId } = req.params as { resourceId: string };
const input = req.body as CreateNoteInput;
try {
const note = await createNote(input, resourceId, req.user);
return res.code(201).send(note);
} catch (err) {
return err;
}
}
export async function listNotesHandler(req: FastifyRequest, res: FastifyReply) {
const { resourceId } = req.params as { resourceId: string };
try {
const notes = await listNotes(resourceId, req.user.tenantId);
return res.code(200).send({ notes: notes });
} catch (err) {
return err;
}
}
export async function updateNoteHandler(
req: FastifyRequest,
res: FastifyReply
) {
const { resourceId, noteId } = req.params as {
resourceId: string;
noteId: string;
};
const input = req.body as CreateNoteInput;
try {
const updatedNote = await updateNote(
input,
resourceId,
noteId,
req.user.tenantId
);
if (!updateNote) return res.code(404).send({ error: "resource not found" });
return res.code(200).send(updatedNote);
} catch (err) {
return err;
}
}
export async function deleteNoteHandler(
req: FastifyRequest,
res: FastifyReply
) {
const { resourceId, noteId } = req.params as {
resourceId: string;
noteId: string;
};
try {
const deleteResult = await deleteNote(
resourceId,
noteId,
req.user.tenantId
);
if (deleteResult.deletedCount == 0)
return res.code(404).send({ error: "resource not found" });
return res.code(204).send();
} catch (err) {
return err;
}
}

79
src/note/note.route.ts Normal file
View File

@@ -0,0 +1,79 @@
import { FastifyInstance } from "fastify";
import {
createNoteHandler,
listNotesHandler,
deleteNoteHandler,
updateNoteHandler,
} from "./note.controller";
import { Claim } from "../utils/claims";
export async function noteRoutes(
fastify: FastifyInstance,
claims: { read: Claim; write: Claim; delete: Claim }
) {
fastify.post(
"/:resourceId/notes",
{
schema: {
params: {
type: "object",
properties: { resourceId: { type: "string" } },
},
},
config: { requiredClaims: [claims.write] },
preHandler: [fastify.authorize],
},
createNoteHandler
);
fastify.get(
"/:resourceId/notes",
{
schema: {
params: {
type: "object",
properties: { resourceId: { type: "string" } },
},
},
config: { requiredClaims: [claims.read] },
preHandler: [fastify.authorize],
},
listNotesHandler
);
fastify.patch(
"/:resourceId/notes/:noteId",
{
schema: {
params: {
type: "object",
properties: {
resourceId: { type: "string" },
noteId: { type: "string" },
},
},
},
config: { requiredClaims: [claims.write] },
preHandler: [fastify.authorize],
},
updateNoteHandler
);
fastify.delete(
"/:resourceId/notes/:noteId",
{
schema: {
params: {
type: "object",
properties: {
resourceId: { type: "string" },
noteId: { type: "string" },
},
},
},
config: { requiredClaims: [claims.write] },
preHandler: [fastify.authorize],
},
deleteNoteHandler
);
}

43
src/note/note.schema.ts Normal file
View File

@@ -0,0 +1,43 @@
import { buildJsonSchemas } from "fastify-zod";
import mongoose from "mongoose";
import { z } from "zod";
const noteSchema = new mongoose.Schema({
tenantId: {
type: String,
required: true,
},
pid: {
type: String,
unique: true,
required: true,
},
resourceId: {
type: String,
required: true,
},
content: {
type: String,
required: true,
},
createdAt: Date,
createdBy: {
type: mongoose.Types.ObjectId,
ref: "user",
},
});
export const noteModel = mongoose.model("note", noteSchema);
const createNoteInput = z.object({
content: z.string(),
});
export type CreateNoteInput = z.infer<typeof createNoteInput>;
export const { schemas: noteSchemas, $ref: $note } = buildJsonSchemas(
{
createNoteInput,
},
{ $id: "note" }
);

83
src/note/note.service.ts Normal file
View File

@@ -0,0 +1,83 @@
import { AuthenticatedUser } from "../auth";
import { generateId } from "../utils/id";
import { CreateNoteInput, noteModel } from "./note.schema";
export async function createNote(
input: CreateNoteInput,
resourceId: string,
user: AuthenticatedUser
) {
return await noteModel.create({
tenantId: user.tenantId,
pid: generateId(),
resourceId: resourceId,
content: input.content,
createdAt: new Date(),
createdBy: user.userId,
});
}
export async function updateNote(
input: CreateNoteInput,
resourceId: string,
noteId: string,
tenantId: string
) {
return await noteModel.findOneAndUpdate(
{
$and: [
{ pid: noteId },
{ tenantId: tenantId },
{ resourceId: resourceId },
],
},
{ ...input },
{ new: true }
);
}
export async function listNotes(resourceId: string, tenantId: string) {
return await noteModel.aggregate([
{
$match: { $and: [{ resourceId: resourceId }, { tenantId: tenantId }] },
},
{
$lookup: {
from: "users",
localField: "createdBy",
foreignField: "_id",
as: "user",
},
},
{
$project: {
_id: 1,
pid: 1,
resourceId: 1,
content: 1,
createdAt: 1,
createdBy: {
$let: {
vars: { user: { $arrayElemAt: ["$user", 0] } },
in: {
_id: "$$user._id",
pid: "$$user.pid",
name: "$$user.name",
avatar: "$$user.avatar",
},
},
},
},
},
]);
}
export async function deleteNote(
resourceId: string,
noteId: string,
tenantId: string
) {
return await noteModel.deleteOne({
$and: [{ pid: noteId }, { tenantId: tenantId }, { resourceId: resourceId }],
});
}

View File

@@ -10,6 +10,12 @@ import {
} from "./permit.controller";
import { $permit } from "./permit.schema";
import { hideFields } from "../auth";
import {
createNoteHandler,
deleteNoteHandler,
listNotesHandler,
} from "../note/note.controller";
import { noteRoutes } from "../note/note.route";
export async function permitRoutes(fastify: FastifyInstance) {
fastify.post(
@@ -111,5 +117,11 @@ export async function permitRoutes(fastify: FastifyInstance) {
getUniqueFieldValuesPermit
);
await noteRoutes(fastify, {
read: "permit:read",
write: "permit:write",
delete: "permit:delete",
});
fastify.addHook("onSend", hideFields("permits"));
}

View File

@@ -9,6 +9,7 @@ import {
updateRtsHandler,
} from "./rts.controller";
import { hideFields } from "../auth";
import { noteRoutes } from "../note/note.route";
export async function rtsRoutes(fastify: FastifyInstance) {
fastify.post(
@@ -94,5 +95,11 @@ export async function rtsRoutes(fastify: FastifyInstance) {
newFilesHandler
);
await noteRoutes(fastify, {
read: "rts:read",
write: "rts:write",
delete: "rts:delete",
});
fastify.addHook("onSend", hideFields("rts"));
}

View File

@@ -15,6 +15,7 @@ import { authRoutes } from "./auth/auth.route";
import { rtsSchemas } from "./rts/rts.schema";
import { taskSchemas } from "./task/task.schema";
import { notificationSchemas } from "./notification/notification.schema";
import { noteSchemas } from "./note/note.schema";
const app = fastify({ logger: true });
@@ -43,6 +44,7 @@ for (const schema of [
...rtsSchemas,
...taskSchemas,
...notificationSchemas,
...noteSchemas,
]) {
app.addSchema(schema);
}

View File

@@ -7,6 +7,7 @@ import {
listTaskHandler,
updateTaskHandler,
} from "./task.controller";
import { noteRoutes } from "../note/note.route";
export async function taskRoutes(fastify: FastifyInstance) {
fastify.post(
@@ -79,4 +80,10 @@ export async function taskRoutes(fastify: FastifyInstance) {
},
deleteTaskHandler
);
await noteRoutes(fastify, {
read: "task:read",
write: "task:write",
delete: "task:delete",
});
}