Skip to content

Commit

Permalink
update (parent notes): few modification done, still work to be done
Browse files Browse the repository at this point in the history
  • Loading branch information
dependentmadani committed Sep 23, 2024
1 parent e14d948 commit 5c6cfc0
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 106 deletions.
15 changes: 12 additions & 3 deletions src/domain/service/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,19 @@ export default class NoteService {
* Get note parent structure recursively by note id and user id
* and check if user has access to the parent note.
* @param noteId - id of the note to get parent structure
* @param userId - id of the user that is requesting the parent structure
* @returns - array of notes that are parent structure of the note
*/
public async getNoteParentStructure(noteId: NoteInternalId, userId: number): Promise<NotePublic[]> {
return await this.noteRepository.getNoteParents(noteId, userId);
public async getNoteParents(noteId: NoteInternalId): Promise<NotePublic[]> {
const noteParents = await this.noteRepository.getNoteParents(noteId);
const noteParentsPublic: NotePublic[] = noteParents.map((note) => {
console.log('note content inside map:', note);

return {
...note,
id: note.publicId,
};
});

return noteParentsPublic;
}
}
80 changes: 41 additions & 39 deletions src/presentation/http/router/note.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,45 +183,47 @@ describe('Note API', () => {
describe('GET note/:notePublicId ', () => {
let context: {
user: User;
user2: User;
anotherUser: User;
parentNote: Note;
childNote: Note;
differentChildNote: Note;
grandChildNote: Note;
} = {
user: {} as User,
user2: {} as User,
anotherUser: {} as User,
parentNote: {} as Note,
childNote: {} as Note,
differentChildNote: {} as Note,
grandChildNote: {} as Note,
};

beforeEach(async () => {
/** Create test user */
context.user = await global.db.insertUser();
if (expect.getState().currentTestName === 'Returns note parents by note public id in different note accessibility and authorization') {
/** Create test user */
context.user = await global.db.insertUser();

context.user2 = await global.db.insertUser();
context.anotherUser = await global.db.insertUser();

/** Create test note - a parent note */
context.parentNote = await global.db.insertNote({
creatorId: context.user.id,
});
/** Create test note - a parent note */
context.parentNote = await global.db.insertNote({
creatorId: context.user.id,
});

/** Create test note - a child note */
context.childNote = await global.db.insertNote({
creatorId: context.user.id,
});
/** Create test note - a child note */
context.childNote = await global.db.insertNote({
creatorId: context.user.id,
});

/** Create test note - create note with different user */
context.differentChildNote = await global.db.insertNote({
creatorId: context.user2.id,
});
/** Create test note - create note with different user */
context.differentChildNote = await global.db.insertNote({
creatorId: context.anotherUser.id,
});

/** Create test note - a grandchild note */
context.grandChildNote = await global.db.insertNote({
creatorId: context.user.id,
});
/** Create test note - a grandchild note */
context.grandChildNote = await global.db.insertNote({
creatorId: context.user.id,
});
}
});

test.each([
Expand Down Expand Up @@ -564,69 +566,69 @@ describe('Note API', () => {
});

test.each([
/** Returns two parents in case of relation between child and parent notes with 200 status */
/** Returns two parents in case of relation between child and parent notes */
{
testCase: 1,
testScenario: 1,
numberOfNotes: 2,
childNoteCreatedByDifferentUser: false,
isPublic: true,
expectedStatusCode: 200,
},
/** Returns multiple parents in case of multiple notes relations with user presence in team in each note with 200 status */
/** Returns multiple parents in case of multiple notes relations with user presence in team in each note */
{
testCase: 2,
testScenario: 2,
numberOfNotes: 3,
childNoteCreatedByDifferentUser: false,
isPublic: true,
expectedStatusCode: 200,
},
/** Returns one parent in case where there is no note relation with 200 status */
/** Returns one parent in case where there is no note relation */
{
testCase: 3,
testScenario: 3,
numberOfNotes: 1,
childNoteCreatedByDifferentUser: false,
isPublic: true,
expectedStatusCode: 200,
},
/** Returns mutiple parents in case where user is not in the team of a note with 200 status */
/** Returns mutiple parents in case where user is not in the team of a note */
{
testCase: 4,
testScenario: 4,
numberOfNotes: 3,
childNoteCreatedByDifferentUser: true,
isPublic: true,
expectedStatusCode: 200,
},
/** Returns multiple parents in case when note is not public with 200 status */
/** Returns multiple parents in case when note is not public */
{
testCase: 5,
testScenario: 5,
numberOfNotes: 3,
childNoteCreatedByDifferentUser: true,
isPublic: false,
expectedStatusCode: 200,
},
/** Returns no note in case when the user is not authorized to note with 403 status */
/** Returns no note in case when the user is not authorized to note */
{
testCase: 6,
testScenario: 6,
numberOfNotes: 2,
childNoteCreatedByDifferentUser: true,
isPublic: false,
expectedStatusCode: 403,
},
/** Returns one note in case when the user has no access to note with 200 status */
/** Returns one note in case when the user has no access to note */
{
testCase: 7,
testScenario: 7,
numberOfNotes: 2,
childNoteCreatedByDifferentUser: true,
isPublic: true,
expectedStatusCode: 200,
},
])('Get note parents in different scenarios', async ({ testCase, numberOfNotes, childNoteCreatedByDifferentUser, isPublic, expectedStatusCode }) => {
])('Returns note parents by note public id in different note accessibility and authorization', async ({ testScenario, numberOfNotes, childNoteCreatedByDifferentUser, isPublic, expectedStatusCode }) => {
if (context !== undefined) {
/** Create acces token for the user */
let accessToken = global.auth(context.user.id);

if (testCase === 6 || testCase == 7) {
accessToken = global.auth(context.user2.id);
if (testScenario === 6 || testScenario == 7) {
accessToken = global.auth(context.anotherUser.id);
}
let noteId = context.parentNote.id;
let notePublicId = context.parentNote.publicId;
Expand Down Expand Up @@ -664,7 +666,7 @@ describe('Note API', () => {
url: `/note/${notePublicId}`,
});

switch (testCase) {
switch (testScenario) {
case (1):
expect(response?.statusCode).toBe(expectedStatusCode);
expect(response?.json()).toMatchObject({
Expand Down
2 changes: 1 addition & 1 deletion src/presentation/http/router/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ const NoteRouter: FastifyPluginCallback<NoteRouterOptions> = (fastify, opts, don
*/
const canEdit = memberRole === MemberRole.Write;

const noteParentStructure = await noteService.getNoteParentStructure(noteId, userId!);
const noteParentStructure = await noteService.getNoteParents(noteId);

return reply.send({
note: notePublic,
Expand Down
1 change: 0 additions & 1 deletion src/repository/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ export async function init(orm: Orm, s3Config: S3StorageConfig): Promise<Reposit
/**
* Create associations between note and team, user and team
*/
noteStorage.createAssociationWithTeamsModel(teamStorage.model);
teamStorage.createAssociationWithNoteModel(noteStorage.model);
teamStorage.createAssociationWithUserModel(userStorage.model);

Expand Down
8 changes: 3 additions & 5 deletions src/repository/note.repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Note, NoteCreationAttributes, NoteInternalId, NotePublicId } from '@domain/entities/note.js';
import type { NotePublic } from '@domain/entities/notePublic.js';
import type NoteStorage from '@repository/storage/note.storage.js';

/**
Expand Down Expand Up @@ -84,12 +83,11 @@ export default class NoteRepository {
}

/**
* Get all notes parents based on note id and user id, by checking team access
* Get all note parents based on note id
* @param noteId : note id to get all its parents
* @param userId : user id to check access
* @returns an array of note parents objects containing public id and content
*/
public async getNoteParents(noteId: NoteInternalId, userId: number): Promise<NotePublic[]> {
return await this.storage.getAllNoteParents(noteId, userId);
public async getNoteParents(noteId: NoteInternalId): Promise<Note[]> {
return await this.storage.getAllNoteParents(noteId);
}
}
67 changes: 10 additions & 57 deletions src/repository/storage/postgres/orm/sequelize/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import type { NoteVisitsModel } from './noteVisits.js';
import type { NoteHistoryModel } from './noteHistory.js';
import type { NoteRelationsModel } from './noteRelations.js';
import { notEmpty } from '@infrastructure/utils/empty.js';
import type { TeamsModel } from './teams.js';
import type { NotePublic } from '@domain/entities/notePublic.js';

/* eslint-disable @typescript-eslint/naming-convention */

Expand Down Expand Up @@ -81,8 +79,6 @@ export default class NoteSequelizeStorage {

public noteRelationModel: typeof NoteRelationsModel | null = null;

public teamModel: typeof TeamsModel | null = null;

/**
* Database instance
*/
Expand Down Expand Up @@ -170,13 +166,6 @@ export default class NoteSequelizeStorage {
this.noteRelationModel = model;
}

public createAssociationWithTeamsModel(model: ModelStatic<TeamsModel>): void {
/**
* Create association with teams
*/
this.teamModel = model;
}

/**
* Insert note to database
* @param options - note creation options
Expand Down Expand Up @@ -348,61 +337,25 @@ export default class NoteSequelizeStorage {

/**
* Get all parent notes of a note that a user has access to,
* by checking the team access.
* where the user has access to.
* @param noteId - the ID of the note.
* @param userId - the ID of the user.
*/
public async getAllNoteParents(noteId: NoteInternalId, userId: number): Promise<NotePublic[]> {
if (!this.teamModel || !this.noteRelationModel) {
throw new Error(`${this.model !== null ? 'TeamStorage: Note relation model is not defined' : 'TeamStorage: Note model is not defined'}`);
public async getAllNoteParents(noteId: NoteInternalId): Promise<Note[]> {
if (!this.noteRelationModel) {
throw new Error('NoteStorage: Note Relation model is not defined');
}

const parentNotes: NotePublic[] = [];
const parentNotes: Note[] = [];
let currentNoteId: NoteInternalId | null = noteId;
/**
* Store notes that user can not access, to check the inherited team if has access
*/
let storeUnaccessibleNote: Note[] = [];

while (currentNoteId != null) {
const teamMember = await this.teamModel.findOne({
where: {
noteId: currentNoteId,
userId,
},
include: {
model: this.model,
as: this.model.tableName,
required: true,
},
// Get the note for database
const note: Note | null = await this.model.findOne({
where: { id: currentNoteId },
});

if (teamMember && notEmpty(teamMember.notes)) {
if (storeUnaccessibleNote.length > 0) {
parentNotes.push(...storeUnaccessibleNote.map(note => ({
id: note.publicId,
content: note.content,
updatedAt: note.updatedAt,
createdAt: note.createdAt,
creatorId: note.creatorId,
})));
storeUnaccessibleNote = [];
}
parentNotes.push({
id: teamMember.notes.publicId,
content: teamMember.notes.content,
updatedAt: teamMember.notes.updatedAt,
createdAt: teamMember.notes.createdAt,
creatorId: teamMember.notes.creatorId,
});
} else if (teamMember === null) {
const note = await this.model.findOne({
where: { id: currentNoteId },
});

if (note !== null) {
storeUnaccessibleNote.push(note);
}
if (notEmpty(note)) {
parentNotes.push(note);
}

// Retrieve the parent note
Expand Down

0 comments on commit 5c6cfc0

Please sign in to comment.