Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"type": "module",
"scripts": {
"start:dev": "tsx watch --env-file=.env src/index.ts",
"start:prod": "tsx watch src/index.ts",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
},
Expand Down
36 changes: 36 additions & 0 deletions backend/src/controllers/notes/get-specific-note.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Context } from "hono";

import { StatusCodes } from "http-status-codes";
import { Types } from "mongoose";

import Note from "@/models/notes.model.js";
import { responseHandler } from "@/utils/response.js";

export default async (c: Context) => {
const noteId = c.req.param("id");
const { userId } = c.get("user");

// Validate ObjectId format
if (!Types.ObjectId.isValid(noteId) || !Types.ObjectId.isValid(userId)) {
return c.json(responseHandler(false, "Invalid note ID or user ID"), StatusCodes.BAD_REQUEST);
}

// Convert to ObjectId
const noteObjectId = new Types.ObjectId(noteId);
const userObjectId = new Types.ObjectId(userId);

// Fetch the note ensuring it belongs to the authenticated user
const note = await Note.findOne({
_id: noteObjectId,
userId: userObjectId,
});

if (!note)
return c.json(responseHandler(false, "Note not found or unauthorized access"), StatusCodes.NOT_FOUND);

return c.json(responseHandler(true, `Fetched the note with Id:${note}`, {
noteId,
userId,
note: note.toObject(),
}), StatusCodes.OK);
};
7 changes: 7 additions & 0 deletions backend/src/models/notes.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,15 @@ const NoteSchema = new Schema<INote>(
}
);

<<<<<<< Updated upstream
<<<<<<< Updated upstream
// 🔥 Indexing for Performance
// Compound index for retrieving notes by user & sorting by creation time
=======
=======
>>>>>>> Stashed changes
// Indexing for Performance
>>>>>>> Stashed changes
NoteSchema.index({ userId: 1, createdAt: -1 });
// Index tags as multi-key field (each tag is indexed for efficient querying)
NoteSchema.index({ tags: 1 });
Expand Down
2 changes: 2 additions & 0 deletions backend/src/routes/notes.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Hono } from "hono";

import createNotesController from "@/controllers/notes/create-notes.controller.js";
import getNotesController from "@/controllers/notes/get-notes.controller.js";
import getSpecificNoteController from "@/controllers/notes/get-specific-note.controller.js";
import updateNotesController from "@/controllers/notes/update-notes.controller.js";
import authMiddleware from "@/middlewares/auth.middleware.js";
import {
Expand All @@ -18,6 +19,7 @@ const useRouter = new Hono<{ Variables: { user: { userId: string } } }>();

useRouter.use(authMiddleware);
useRouter.get("/", validateRequestDto(undefined, getNotesQuerySchema), getNotesController);
useRouter.get("/:id", validateRequestDto(undefined, undefined, NotesParamsSchema), getSpecificNoteController);
useRouter.post("/", validateRequestDto(createNoteSchema), createNotesController);
useRouter.patch("/:id", validateRequestDto(updateNoteSchema, undefined, NotesParamsSchema), updateNotesController);
useRouter.delete("/:id", validateRequestDto(undefined, undefined, NotesParamsSchema), deleteNotesController)
Expand Down
21 changes: 21 additions & 0 deletions backend/src/validations/schemas/notes.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,39 @@ export const getNotesQuerySchema = z.object({

// Zod schema for creating new note
export const createNoteSchema = z.object({
<<<<<<< Updated upstream
title: z.string().min(1, "Title is required").max(255),
content: z.string().min(1, "Content is required"),
images: z.array(z.string().url()).optional().default([]),
favorite: z.boolean().optional().default(false),
pinned: z.boolean().optional().default(false),
tags: z.array(z.string()).optional().default([]), // Must be an array of strings
=======
title: z.string()
.min(1, "Title is required")
.max(255)
.trim(),
// content: z.array(z.any()),
content: z.string().min(1, "Content can't be empty"),
images: z.array(z.string().url()).optional().default([]), // Must be valid URLs
favorite: z.boolean().optional().default(false), // Defaults to false
pinned: z.boolean().optional().default(false), // Defaults to false
tags: z.array(z.string().trim().min(1)).max(10).optional().default([]),
>>>>>>> Stashed changes
});

// Zod schema for note update
export const updateNoteSchema = z.object({
// noteId: z.string({ message: "NoteId is required for updating it" }).min(1, "NoteId is required for updating it"),
title: z.string().min(1, "Title is required").max(255).optional(),
<<<<<<< Updated upstream
<<<<<<< Updated upstream
=======
// content: z.array(z.any()).optional(),
>>>>>>> Stashed changes
=======
// content: z.array(z.any()).optional(),
>>>>>>> Stashed changes
content: z.string().optional(),
images: z.array(z.string().url()).optional(),
favorite: z.boolean().optional(),
Expand Down