feat(project): update status project ke completed dan apply restrictionnya
This commit is contained in:
@@ -740,6 +740,9 @@ class ProjectService {
|
||||
if (!project) {
|
||||
return error(new NotFoundError("Project not found"));
|
||||
}
|
||||
if (project.status !== "active") {
|
||||
return error(new ConflictError("Cannot remove member from a non-active project"));
|
||||
}
|
||||
|
||||
const user = await projectRepository.findUserByIdAndActive(id_user);
|
||||
if (!user) {
|
||||
|
||||
@@ -63,6 +63,7 @@ class TaskRepository {
|
||||
slug: true,
|
||||
project_name: true,
|
||||
project_icon: true,
|
||||
status: true,
|
||||
members: {
|
||||
where: {
|
||||
status: 'active',
|
||||
@@ -159,6 +160,7 @@ class TaskRepository {
|
||||
select: {
|
||||
id: true,
|
||||
project_name: true,
|
||||
status: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -236,6 +238,7 @@ class TaskRepository {
|
||||
slug: true,
|
||||
project_name: true,
|
||||
project_icon: true,
|
||||
status: true,
|
||||
members: {
|
||||
where: {
|
||||
status: 'active',
|
||||
|
||||
@@ -35,6 +35,11 @@ class TaskService {
|
||||
return error(accessError);
|
||||
}
|
||||
|
||||
const lockError = this.validateProjectIsActive(project, 'create task');
|
||||
if (lockError) {
|
||||
return error(lockError);
|
||||
}
|
||||
|
||||
const taskSlug = await this.generateUniqueTaskSlug(project.id, payload.title);
|
||||
const deadlineAt = this.buildDeadlineAt(payload.deadline_date, payload.specific_time);
|
||||
|
||||
@@ -159,11 +164,15 @@ class TaskService {
|
||||
}
|
||||
|
||||
const accessError = await this.validateProjectAccess(existingTask.id_project, actor);
|
||||
|
||||
if (accessError) {
|
||||
return error(accessError);
|
||||
}
|
||||
|
||||
const lockError = this.validateProjectIsActive(existingTask.project, 'update task');
|
||||
if (lockError) {
|
||||
return error(lockError);
|
||||
}
|
||||
|
||||
const submissionCount = await taskRepository.countSubmissionsByTask(existingTask.id);
|
||||
|
||||
if (
|
||||
@@ -225,11 +234,15 @@ class TaskService {
|
||||
}
|
||||
|
||||
const accessError = await this.validateProjectAccess(task.id_project, actor);
|
||||
|
||||
if (accessError) {
|
||||
return error(accessError);
|
||||
}
|
||||
|
||||
const lockError = this.validateProjectIsActive(task.project, 'delete task');
|
||||
if (lockError) {
|
||||
return error(lockError);
|
||||
}
|
||||
|
||||
const submissionCount = await taskRepository.countSubmissionsByTask(task.id);
|
||||
|
||||
if (submissionCount > 0) {
|
||||
@@ -255,11 +268,15 @@ class TaskService {
|
||||
}
|
||||
|
||||
const task = await this.resolveTask(idTask, projectIdentifier);
|
||||
|
||||
if (!task) {
|
||||
return error(new NotFoundError('Task not found'));
|
||||
}
|
||||
|
||||
const lockError = this.validateProjectIsActive(task.project, 'submit task');
|
||||
if (lockError) {
|
||||
return error(lockError);
|
||||
}
|
||||
|
||||
const membership = await taskRepository.checkActiveProjectMember(task.id_project, actor.id);
|
||||
|
||||
if (!membership) {
|
||||
@@ -334,17 +351,14 @@ class TaskService {
|
||||
if (!this.isPositiveInteger(idSubmission)) {
|
||||
return error(new BadRequestError('Submission ID must be a valid number'));
|
||||
}
|
||||
|
||||
if (!actor?.id || actor.role !== 'intern') {
|
||||
return error(new ForbiddenError('Access denied: only intern can update submission'));
|
||||
}
|
||||
|
||||
const submission = await taskRepository.findSubmissionById(idSubmission);
|
||||
|
||||
if (!submission) {
|
||||
return error(new NotFoundError('Submission not found'));
|
||||
}
|
||||
|
||||
if (submission.id_user !== parseInt(actor.id)) {
|
||||
return error(new ForbiddenError('Access denied: you can only update your own submission'));
|
||||
}
|
||||
@@ -353,11 +367,18 @@ class TaskService {
|
||||
submission.task.id_project,
|
||||
actor.id
|
||||
);
|
||||
|
||||
if (!membership) {
|
||||
return error(new ForbiddenError('Access denied: you are not a member of this project'));
|
||||
}
|
||||
|
||||
const lockError = this.validateProjectIsActive(
|
||||
submission.task.project,
|
||||
'update submission'
|
||||
);
|
||||
if (lockError) {
|
||||
return error(lockError);
|
||||
}
|
||||
|
||||
const updateData = {};
|
||||
|
||||
if (submission.task.submission_type === 'file_upload') {
|
||||
@@ -404,17 +425,14 @@ class TaskService {
|
||||
if (!this.isPositiveInteger(idSubmission)) {
|
||||
return error(new BadRequestError('Submission ID must be a valid number'));
|
||||
}
|
||||
|
||||
if (!actor?.id || actor.role !== 'intern') {
|
||||
return error(new ForbiddenError('Access denied: only intern can delete submission'));
|
||||
}
|
||||
|
||||
const submission = await taskRepository.findSubmissionById(idSubmission);
|
||||
|
||||
if (!submission) {
|
||||
return error(new NotFoundError('Submission not found'));
|
||||
}
|
||||
|
||||
if (submission.id_user !== parseInt(actor.id)) {
|
||||
return error(new ForbiddenError('Access denied: you can only delete your own submission'));
|
||||
}
|
||||
@@ -423,11 +441,18 @@ class TaskService {
|
||||
submission.task.id_project,
|
||||
actor.id
|
||||
);
|
||||
|
||||
if (!membership) {
|
||||
return error(new ForbiddenError('Access denied: you are not a member of this project'));
|
||||
}
|
||||
|
||||
const lockError = this.validateProjectIsActive(
|
||||
submission.task.project,
|
||||
'delete submission'
|
||||
);
|
||||
if (lockError) {
|
||||
return error(lockError);
|
||||
}
|
||||
|
||||
await taskRepository.deleteSubmission(idSubmission);
|
||||
|
||||
this.deleteLocalSubmissionFile(submission.file_path);
|
||||
@@ -470,6 +495,20 @@ class TaskService {
|
||||
return new ForbiddenError('Access denied: invalid role');
|
||||
}
|
||||
|
||||
validateProjectIsActive(project, action = 'modify this project') {
|
||||
if (!project) {
|
||||
return new NotFoundError('Project not found');
|
||||
}
|
||||
|
||||
if (project.status !== 'active') {
|
||||
return new ConflictError(
|
||||
`Cannot ${action} because this project is already ${project.status}`
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
isMentorOrAdmin(actor) {
|
||||
return actor?.role === 'admin' || actor?.role === 'mentor';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user