feat: Nambahin API untuk hapusin member dari project

This commit is contained in:
Rafi Athallah
2026-06-26 10:46:18 +07:00
parent 5e77286fcc
commit 5e930ccbff
4 changed files with 197 additions and 1 deletions
@@ -267,6 +267,27 @@ class ProjectController {
);
}
}
async removeMember(req, res) {
try {
const actor = getActor(req);
const result = await projectService.removeMember(req.body, actor);
if (result.err) {
return response(res, 'fail', result);
}
return response(res, 'success', result, 'Member removed successfully', SUCCESS.OK);
} catch (err) {
return response(
res,
'fail',
error(new InternalServerError(err.message)),
'Unexpected error occurred',
ERROR.INTERNAL_ERROR
);
}
}
}
module.exports = new ProjectController();
@@ -571,6 +571,54 @@ class ProjectService {
}
}
async removeMember(payload, actor = {}) {
try {
if (!actor?.id) {
return error(new BadRequestError("Admin ID is required"));
}
if (actor.role !== "admin" && actor.role !== "mentor") {
return error(
new ForbiddenError("Access denied: only mentors/admins can remove members"),
);
}
const { id_project, id_user } = payload;
if (!id_project || !id_user) {
return error(new BadRequestError("Project ID and User ID are required"));
}
const project = await projectRepository.findById(id_project);
if (!project) {
return error(new NotFoundError("Project not found"));
}
const user = await projectRepository.findUserByIdAndActive(id_user);
if (!user) {
return error(new NotFoundError("User not found or inactive"));
}
const existingMembership = await projectRepository.findMembership(id_project, id_user);
if (!existingMembership || existingMembership.status !== 'active') {
return error(new BadRequestError("User is not an active member of this project"));
}
const membership = await projectRepository.updateMembershipStatus(existingMembership.id, 'removed');
await notificationService.createNotificationForIntern(
id_user,
"Dikeluarkan dari Proyek",
`Anda telah dikeluarkan dari proyek '${project.project_name}'.`
).catch(err => console.error("Failed to send project removal notification:", err));
return data(membership);
} catch (err) {
return error(err);
}
}
async generateUniqueProjectSlug(projectName, excludeProjectId = null) {
const baseSlug = slugify(projectName, 'project');
+55
View File
@@ -852,4 +852,59 @@ router.get('/interns', verifyJWT, isMentorOrAdmin, projectController.getInterns)
*/
router.post('/assign-member', verifyJWT, isMentorOrAdmin, projectController.assignMember);
/**
* @swagger
* /project-api/remove-member:
* post:
* summary: Remove an intern from a project
* description: Removes an intern from a project by project ID and user ID. Only accessible by mentor/admin.
* tags: [Project]
* security:
* - bearerAuth: []
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - id_project
* - id_user
* properties:
* id_project:
* type: integer
* example: 1
* id_user:
* type: integer
* example: 2
* responses:
* 200:
* description: Member removed successfully
* content:
* application/json:
* schema:
* type: object
* properties:
* status:
* type: boolean
* example: true
* message:
* type: string
* example: Member removed successfully
* code:
* type: integer
* example: 200
* 400:
* description: Bad request
* 401:
* description: Unauthorized
* 403:
* description: Forbidden (Only for admin/mentors)
* 404:
* description: Project or User not found
* 500:
* description: Internal server error
*/
router.post('/remove-member', verifyJWT, isMentorOrAdmin, projectController.removeMember);
module.exports = router;