Skip to content
Merged
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
14 changes: 14 additions & 0 deletions src/domain/service/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,20 @@ export default class NoteService {
};
}

/**
* Returns notes created by user, ordered by creation time
* @param userId - id of the user
* @param page - number of current page
* @returns list of the notes ordered by creation time
*/
public async getNotesByCreatorId(userId: User['id'], page: number): Promise<NoteList> {
const offset = (page - 1) * this.noteListPortionSize;

return {
items: await this.noteRepository.getNotesByCreatorId(userId, offset, this.noteListPortionSize),
};
}

/**
* Create note relation
* @param noteId - id of the current note
Expand Down
130 changes: 130 additions & 0 deletions src/presentation/http/router/noteList.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,133 @@ describe('GET /notes?page', () => {
}
});
});

describe('GET /notes/created?page', () => {
test.each([
/**
* Returns noteList with specified length (not for last page)
* User is authorized, notes are created by user
*/
{
isAuthorized: true,
expectedStatusCode: 200,
notesCreated: true,
expectedMessage: null,
expectedLength: 30,
pageNumber: 1,
},
/**
* Returns noteList with specified length (for last page)
* User is authorized, notes are created by user
*/
{
isAuthorized: true,
expectedStatusCode: 200,
notesCreated: true,
expectedMessage: null,
expectedLength: 19,
pageNumber: 2,
},
/**
* Returns noteList with no items if there are no notes for certain page
* User is authorized, notes are created by user
*/
{
isAuthorized: true,
expectedStatusCode: 200,
notesCreated: true,
expectedMessage: null,
expectedLength: 0,
pageNumber: 3,
},
/**
* Returns 'querystring/page must be >= 1' message when page < 0
*/
{
isAuthorized: true,
expectedStatusCode: 400,
notesCreated: true,
expectedMessage: 'querystring/page must be >= 1',
expectedLength: 0,
pageNumber: -1,
},
/**
* Returns 'querystring/page must be <= 30' message when page is too large (maximum page numbrer is 30 by default)
*/
{
isAuthorized: true,
expectedStatusCode: 400,
notesCreated: true,
expectedMessage: 'querystring/page must be <= 30',
expectedLength: 0,
pageNumber: 31,
},
/**
* Returns 'unauthorized' message when user is not authorized
*/
{
isAuthorized: false,
expectedStatusCode: 401,
notesCreated: true,
expectedMessage: 'You must be authenticated to access this resource',
expectedLength: 0,
pageNumber: 1,
},
/**
* Returns noteList with no items if user did not create any notes
* User is authorized, notes are not created by user
*/
{
isAuthorized: true,
expectedStatusCode: 200,
notesCreated: false,
expectedMessage: null,
expectedLength: 0,
pageNumber: 1,
},
])('Get note list created by user', async ({ isAuthorized, expectedStatusCode, notesCreated, expectedMessage, expectedLength, pageNumber }) => {
const portionSize = 49;
let accessToken;

/** Insert creator and randomGuy */
const creator = await global.db.insertUser();

const randomGuy = await global.db.insertUser();

if (isAuthorized) {
accessToken = global.auth(randomGuy.id);
}

for (let i = 0; i < portionSize; i++) {
const note = await global.db.insertNote({
creatorId: notesCreated ? randomGuy.id : creator.id,
});

await global.db.insertNoteSetting({
noteId: note.id,
cover: 'DZnvqi63.png',
isPublic: false,
});
}

const response = await global.api?.fakeRequest({
method: 'GET',
headers: {
authorization: `Bearer ${accessToken}`,
},
url: `/notes/created?page=${pageNumber}`,
});

const body = response?.json();

if (expectedMessage !== null) {
expect(response?.statusCode).toBe(expectedStatusCode);

expect(body.message).toBe(expectedMessage);
} else {
expect(response?.statusCode).toBe(expectedStatusCode);

expect(body.items).toHaveLength(expectedLength);
}
});
});
54 changes: 54 additions & 0 deletions src/presentation/http/router/noteList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,60 @@ const NoteListRouter: FastifyPluginCallback<NoteListRouterOptions> = (fastify, o
return reply.send(noteListPublic);
});

/**
* Get note list created by user, ordered by creation time
*/
fastify.get<{
Querystring: {
page: number;
};
}>('/created', {
config: {
policy: [
'authRequired',
],
},
schema: {
querystring: {
page: {
type: 'number',
minimum: 1,
maximum: 30,
},
},

response: {
'2xx': {
description: 'Query notelist',
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.getNotesByCreatorId(userId, page);
/**
* Wrapping Notelist for public use
*/
const noteListItemsPublic: NotePublic[] = noteList.items.map(definePublicNote);

const noteListPublic: NoteListPublic = {
items: noteListItemsPublic,
};

return reply.send(noteListPublic);
});

done();
};

Expand Down
10 changes: 10 additions & 0 deletions src/repository/note.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ export default class NoteRepository {
return await this.storage.getRecentNotesByUserId(id, offset, limit);
}

/**
* Gets notes created by user, ordered by creation time
* @param creatorId - note creator id
* @param offset - number of skipped notes
* @param limit - number of notes to get
*/
public async getNotesByCreatorId(creatorId: number, offset: number, limit: number): Promise<Note[]> {
return await this.storage.getNotesByCreatorId(creatorId, offset, limit);
}

/**
* Get all notes based on their ids
* @param noteIds : list of note ids
Expand Down
49 changes: 49 additions & 0 deletions src/repository/storage/postgres/orm/sequelize/note.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,55 @@ export default class NoteSequelizeStorage {
});
}

/**
* Gets notes created by user, ordered by creation time
* @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 creation time
*/
public async getNotesByCreatorId(creatorId: number, offset: number, limit: number): Promise<Note[]> {
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: [
['createdAt', '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
Expand Down
Loading