Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: route for editing team member role #155

Merged
merged 20 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 18 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
11 changes: 11 additions & 0 deletions src/domain/service/noteSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,15 @@ export default class NoteSettingsService {
public async createTeamMember(team: TeamMemberCreationAttributes): Promise<TeamMember> {
return await this.teamRepository.createTeamMembership(team);
}

/**
*
TatianaFomina marked this conversation as resolved.
Show resolved Hide resolved
* @param id - userId of team member
* @param noteId - note internal id
* @param role - new team member role
* @returns returns 1 if the role has been changed and 0 otherwise
*/
public async patchMemberRoleByUserId(id: TeamMember['id'], noteId: NoteInternalId, role: MemberRole): Promise<MemberRole | null> {
return await this.teamRepository.patchMemberRoleByUserId(id, noteId, role);
}
}
2 changes: 1 addition & 1 deletion src/presentation/http/router/join.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('Join API', () => {

expect(response?.json()).toStrictEqual({
result: {
id: 2,
id: 3,
userId,
noteId: 1,
role: 0,
Expand Down
71 changes: 71 additions & 0 deletions src/presentation/http/router/noteSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,4 +281,75 @@ describe('NoteSettings API', () => {

test.todo('Return 403 when user authorized, but not member of the team');
});

describe('PATCH /note-teams/new-role/:newRole', () => {
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
test('Update team member role by user id and note id, with status code 200', async () => {
// patch member role of existing team member
const response = await global.api?.fakeRequest({
TatianaFomina marked this conversation as resolved.
Show resolved Hide resolved
method: 'PATCH',
headers: {
authorization: `Bearer ${global.auth(1)}`,
},
url: '/note-settings/Pq1T9vc23Q/team',
body: {
userId: 1,
newRole: 1,
},
});

expect(response?.statusCode).toBe(200);

// check if we changed role correctly
const team = await global.api?.fakeRequest({
method: 'GET',
headers: {
authorization: `Bearer ${global.auth(1)}`,
},
url: '/note-settings/Pq1T9vc23Q/team',
});

expect(team?.json()).toStrictEqual([
{
'id': 2,
'noteId': 2,
'userId': 1,
'role': 1,
},
]);
});

test('Returns status code 200 and new role, if role was patched (if the user already had passing a role, then behavior is the same)', async () => {
const response = await global.api?.fakeRequest({
method: 'PATCH',
headers: {
authorization: `Bearer ${global.auth(1)}`,
},
url: '/note-settings/Pq1T9vc23Q/team',
body: {
userId: 1,
newRole: 1,
},
});

expect(response?.statusCode).toBe(200);
expect(response?.body).toBe('1');
});

test('Returns status code 404 and "User does not belong to Note\'s team" message if no such a note exists', async () => {
const response = await global.api?.fakeRequest({
method: 'PATCH',
headers: {
authorization: `Bearer ${global.auth(1)}`,
},
url: '/note-settings/73NdxFZ4k7/team',
body: {
userId: 15,
newRole: 1,
},
});

expect(response?.statusCode).toBe(404);
expect(response?.json().message).toBe('User does not belong to Note\'s team');
});
});
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
});
47 changes: 45 additions & 2 deletions src/presentation/http/router/noteSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import useNoteResolver from '../middlewares/note/useNoteResolver.js';
import type NoteService from '@domain/service/note.js';
import useNoteSettingsResolver from '../middlewares/noteSettings/useNoteSettingsResolver.js';
import type { NotePublicId } from '@domain/entities/note.js';
import type { Team } from '@domain/entities/team.js';
import type { Team, MemberRole } from '@domain/entities/team.js';
import type User from '@domain/entities/user.js';

/**
* Interface for the note settings router.
Expand Down Expand Up @@ -89,6 +90,47 @@ const NoteSettingsRouter: FastifyPluginCallback<NoteSettingsRouterOptions> = (fa
return reply.send(noteSettings);
});

/**
* Patch team member role by user and note id
*
* @todo add policy for this route to check id user have 'write' role if this team to patch someone's else role
*/
fastify.patch<{
Params: {
notePublicId: NotePublicId,
},
Body: {
userId: User['id'],
newRole: MemberRole,
},
Reply: MemberRole,
}>('/:notePublicId/team', {
config: {
policy: [
'authRequired',
],
neSpecc marked this conversation as resolved.
Show resolved Hide resolved
},
schema: {
params: {
notePublicId: {
$ref: 'NoteSchema#/properties/id',
},
},
},
preHandler: [
noteResolver,
],
}, async (request, reply) => {
const noteId = request.note?.id as number;
const newRole = await noteSettingsService.patchMemberRoleByUserId(request.body.userId, noteId, request.body.newRole);

if (newRole === null) {
return reply.notFound('User does not belong to Note\'s team');
}

return reply.send(newRole);
});

/**
* Patch noteSettings by note id
*/
Expand Down Expand Up @@ -141,7 +183,8 @@ const NoteSettingsRouter: FastifyPluginCallback<NoteSettingsRouterOptions> = (fa

/**
* Get team by note id
* TODO add policy for this route (check if user is collaborator)
*
* @todo add policy for this route (check if user is collaborator)
*/
fastify.get<{
Params: {
Expand Down
22 changes: 22 additions & 0 deletions src/repository/storage/postgres/orm/sequelize/teams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MemberRole } from '@domain/entities/team.js';
import type User from '@domain/entities/user.js';
import type { NoteInternalId } from '@domain/entities/note.js';


/**
* Class representing a teams model in database
*/
Expand Down Expand Up @@ -220,4 +221,25 @@ export default class TeamsSequelizeStorage {

return affectedRows > 0;
}

/**
*
TatianaFomina marked this conversation as resolved.
Show resolved Hide resolved
* @param userId - id of team member
* @param noteId - note internal id
* @param role - new team member role
* @returns returns 1 if the role has been changed and 0 otherwise
*/
public async patchMemberRoleById(userId: TeamMember['id'], noteId: NoteInternalId, role: MemberRole): Promise<MemberRole | null> {
const affectedRows = await this.model.update({
role: role,
}, {
where: {
userId,
noteId,
},
});

// if counter of affected rows is more than 0, then we return new role
return affectedRows[0] ? role : null;
}
}
12 changes: 11 additions & 1 deletion src/repository/team.repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type TeamStorage from '@repository/storage/team.storage.js';
import type { MemberRole, Team, TeamMember, TeamMemberCreationAttributes } from '@domain/entities/team.js';
import type { Team, TeamMember, TeamMemberCreationAttributes, MemberRole } from '@domain/entities/team.js';
import type { NoteInternalId } from '@domain/entities/note';
import type User from '@domain/entities/user';

Expand Down Expand Up @@ -71,4 +71,14 @@ export default class TeamRepository {
public async removeMemberById(id: TeamMember['id']): Promise<boolean> {
return await this.storage.removeTeamMemberById(id);
}
/**
*
TatianaFomina marked this conversation as resolved.
Show resolved Hide resolved
* @param id - id of team member
* @param noteId - note internal id
* @param role - team member new role
* @returns returns 1 if the role has been changed and 0 otherwise
*/
public async patchMemberRoleByUserId(id: TeamMember['id'], noteId: NoteInternalId, role : MemberRole): Promise<MemberRole | null> {
return await this.storage.patchMemberRoleById(id, noteId, role);
}
}
6 changes: 6 additions & 0 deletions src/tests/test-data/note-teams.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,11 @@
"note_id": 1,
"user_id": 2,
"role": 0
},
{
"id": 2,
"note_id": 2,
"user_id": 1,
"role": 0
}
]
Loading