add notes routes
This commit is contained in:
79
src/note/note.controller.ts
Normal file
79
src/note/note.controller.ts
Normal 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
79
src/note/note.route.ts
Normal 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
43
src/note/note.schema.ts
Normal 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
83
src/note/note.service.ts
Normal 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 }],
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user