From f348312839ac154848facecad7cdafaebc31ebd0 Mon Sep 17 00:00:00 2001 From: Dobrunia Kostrigin <48620984+Dobrunia@users.noreply.github.com> Date: Fri, 7 Nov 2025 20:56:26 +0300 Subject: [PATCH] feat: add my notes endpoint --- src/domain/service/note.ts | 18 ++++++ src/presentation/http/router/noteList.ts | 57 ++++++++++++++++++- src/repository/note.repository.ts | 10 ++++ .../storage/postgres/orm/sequelize/note.ts | 55 +++++++++++++++++- 4 files changed, 136 insertions(+), 4 deletions(-) diff --git a/src/domain/service/note.ts b/src/domain/service/note.ts index c4ae5b52..d6b5591c 100644 --- a/src/domain/service/note.ts +++ b/src/domain/service/note.ts @@ -238,6 +238,24 @@ export default class NoteService { }; } + /** + * Returns note list created by user + * @param creatorId - id of the note creator + * @param page - number of current page + * @returns list of the notes ordered by updatedAt DESC + */ + public async getMyNoteList(creatorId: User['id'], page: number): Promise { + const offset = (page - 1) * this.noteListPortionSize; + + return { + items: await this.noteRepository.getMyNoteList( + creatorId, + offset, + this.noteListPortionSize + ), + }; + } + /** * Create note relation * @param noteId - id of the current note diff --git a/src/presentation/http/router/noteList.ts b/src/presentation/http/router/noteList.ts index 49507d2f..d91d49b4 100644 --- a/src/presentation/http/router/noteList.ts +++ b/src/presentation/http/router/noteList.ts @@ -11,7 +11,6 @@ interface NoteListRouterOptions { * Note service instance */ noteService: NoteService; - } /** @@ -77,6 +76,62 @@ const NoteListRouter: FastifyPluginCallback = (fastify, o return reply.send(noteListPublic); }); + /** + * Get note list created by the user + */ + fastify.get<{ + Querystring: { + page: number; + }; + }>( + '/my', + { + config: { + policy: ['authRequired'], + }, + schema: { + querystring: { + page: { + type: 'number', + minimum: 1, + maximum: 30, + }, + }, + + response: { + '2xx': { + description: 'Query notelist created by user', + properties: { + items: { + id: { type: 'string' }, + content: { type: 'string' }, + createdAt: { type: 'string' }, + creatorId: { type: 'string' }, + updatedAt: { type: 'string' }, + }, + }, + }, + }, + }, + }, + async (request, reply) => { + const userId = request.userId as number; + const page = request.query.page; + + const noteList = await noteService.getMyNoteList(userId, page); + /** + * Wrapping Notelist for public use + */ + const noteListItemsPublic: NotePublic[] = noteList.items.map(definePublicNote); + + const noteListPublic: NoteListPublic = { + items: noteListItemsPublic, + }; + + return reply.send(noteListPublic); + } + ); + done(); }; diff --git a/src/repository/note.repository.ts b/src/repository/note.repository.ts index 234c0741..daad0746 100644 --- a/src/repository/note.repository.ts +++ b/src/repository/note.repository.ts @@ -82,6 +82,16 @@ export default class NoteRepository { return await this.storage.getNoteListByUserId(id, offset, limit); } + /** + * Gets note list created by user + * @param creatorId - id of note creator + * @param offset - number of skipped notes + * @param limit - number of notes to get + */ + public async getMyNoteList(creatorId: number, offset: number, limit: number): Promise { + return await this.storage.getMyNoteList(creatorId, offset, limit); + } + /** * Get all notes based on their ids * @param noteIds : list of note ids diff --git a/src/repository/storage/postgres/orm/sequelize/note.ts b/src/repository/storage/postgres/orm/sequelize/note.ts index 1b9ba87c..ef99a856 100644 --- a/src/repository/storage/postgres/orm/sequelize/note.ts +++ b/src/repository/storage/postgres/orm/sequelize/note.ts @@ -285,6 +285,55 @@ export default class NoteSequelizeStorage { }); } + /** + * Gets note list created by user + * @param creatorId - id of note creator + * @param offset - number of skipped notes + * @param limit - number of notes to get + * @returns list of the notes ordered by updatedAt DESC + */ + public async getMyNoteList(creatorId: number, offset: number, limit: number): Promise { + if (!this.settingsModel) { + throw new Error('NoteStorage: Note settings model not initialized'); + } + + const reply = await this.model.findAll({ + offset: offset, + limit: limit, + where: { + creatorId: creatorId, + }, + order: [['updatedAt', 'DESC']], + include: [ + { + model: this.settingsModel, + as: 'noteSettings', + attributes: ['cover'], + duplicating: false, + }, + ], + }); + + /** + * Convert note model data to Note entity with cover property + */ + return reply.map((note) => { + return { + id: note.id, + /** + * noteSettings is required to be, because we make join + */ + cover: note.noteSettings!.cover, + content: note.content, + updatedAt: note.updatedAt, + createdAt: note.createdAt, + publicId: note.publicId, + creatorId: note.creatorId, + tools: note.tools, + }; + }); + } + /** * Gets note by id * @param hostname - custom hostname @@ -356,7 +405,7 @@ export default class NoteSequelizeStorage { // Fetch all notes and relations in a recursive query const query = ` WITH RECURSIVE note_tree AS ( - SELECT + SELECT n.id AS "noteId", n.content, n.public_id AS "publicId", @@ -364,10 +413,10 @@ export default class NoteSequelizeStorage { FROM ${String(this.database.literal(this.tableName).val)} n LEFT JOIN ${String(this.database.literal('note_relations').val)} nr ON n.id = nr.note_id WHERE n.id = :startNoteId - + UNION ALL - SELECT + SELECT n.id AS "noteId", n.content, n.public_id AS "publicId",