diff --git a/prisma/migrations/20260706134239_add_link_to_notification/migration.sql b/prisma/migrations/20260706134239_add_link_to_notification/migration.sql new file mode 100644 index 0000000..8365a4f --- /dev/null +++ b/prisma/migrations/20260706134239_add_link_to_notification/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `notification` ADD COLUMN `link` TEXT NULL; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d9cca46..566af11 100755 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -380,6 +380,7 @@ model Notification { id_admin Int? // For mentors/admins title String @db.VarChar(255) message String @db.Text + link String? @db.Text is_read Boolean @default(false) created_at DateTime @default(now()) diff --git a/src/modules/notification/services/notification.service.js b/src/modules/notification/services/notification.service.js index 003bee7..4069576 100644 --- a/src/modules/notification/services/notification.service.js +++ b/src/modules/notification/services/notification.service.js @@ -5,13 +5,14 @@ const { data, error } = require('../../../helpers/utils/wrapper'); const { NotFoundError, ForbiddenError, BadRequestError } = require('../../../helpers/error'); class NotificationService { - async createNotificationForIntern(userId, title, message) { + async createNotificationForIntern(userId, title, message, link = '') { try { const notification = await notificationRepository.create({ id_user: parseInt(userId), id_admin: null, title, message, + link, is_read: false }); @@ -26,13 +27,14 @@ class NotificationService { } } - async createNotificationForMentor(adminId, title, message) { + async createNotificationForMentor(adminId, title, message, link = '') { try { const notification = await notificationRepository.create({ id_user: null, id_admin: parseInt(adminId), title, message, + link, is_read: false }); @@ -47,7 +49,7 @@ class NotificationService { } } - async createNotificationForProjectInterns(projectId, title, message) { + async createNotificationForProjectInterns(projectId, title, message, link = '') { try { const project = await taskRepository.findProjectById(projectId); if (!project || !project.members) { @@ -56,7 +58,7 @@ class NotificationService { const results = []; for (const member of project.members) { - const res = await this.createNotificationForIntern(member.id_user, title, message); + const res = await this.createNotificationForIntern(member.id_user, title, message, link); if (res.data) { results.push(res.data); } diff --git a/src/modules/project/services/project.service.js b/src/modules/project/services/project.service.js index 80b02f7..a5cf7ed 100644 --- a/src/modules/project/services/project.service.js +++ b/src/modules/project/services/project.service.js @@ -97,7 +97,8 @@ class ProjectService { await notificationService.createNotificationForIntern( idUser, "Diterima ke Proyek", - `Anda telah bergabung ke proyek '${project.project_name}'.` + `Anda telah bergabung ke proyek '${project.project_name}'.`, + `/intern/projects/${project.slug}` ).catch(err => console.error("Failed to send project assignment notification:", err)); } @@ -711,7 +712,8 @@ class ProjectService { await notificationService.createNotificationForIntern( id_user, "Diterima ke Proyek", - `Anda telah bergabung ke proyek '${project.project_name}'.` + `Anda telah bergabung ke proyek '${project.project_name}'.`, + `/intern/projects/${project.slug}` ).catch(err => console.error("Failed to send project assignment notification:", err)); return data(membership); diff --git a/src/modules/task/services/task.service.js b/src/modules/task/services/task.service.js index 85b44e0..9b27028 100644 --- a/src/modules/task/services/task.service.js +++ b/src/modules/task/services/task.service.js @@ -55,7 +55,8 @@ class TaskService { await notificationService.createNotificationForProjectInterns( project.id, "Tugas Baru Ditambahkan", - `Mentor telah membuat tugas baru: '${task.title}' di proyek '${project.project_name}'.` + `Mentor telah membuat tugas baru: '${task.title}' di proyek '${project.project_name}'.`, + `/intern/projects/${project.slug}/${task.slug}` ).catch(err => console.error("Failed to send task creation notifications:", err)); return data(this.mapTask(task)); diff --git a/src/routes/notification.routes.js b/src/routes/notification.routes.js index 2e18500..cd7a99b 100644 --- a/src/routes/notification.routes.js +++ b/src/routes/notification.routes.js @@ -28,6 +28,10 @@ const router = express.Router(); * message: * type: string * example: "Mentor telah menambahkan tugas baru." + * link: + * type: string + * nullable: true + * example: "/intern/projects/some-project-slug/some-task-slug" * is_read: * type: boolean * example: false diff --git a/test/test_notifications.js b/test/test_notifications.js index c3cb002..1476d23 100644 --- a/test/test_notifications.js +++ b/test/test_notifications.js @@ -7,11 +7,14 @@ const BASE_URL = 'http://localhost:9000'; async function runTests() { console.log('=== STARTING INTEGRATION TESTS FOR NOTIFICATION SYSTEM ===\n'); - // 0. Clean up existing memberships for rafi@student.com (user ID 1) to allow project assignment - console.log('0. Cleaning up existing project memberships for rafi@student.com...'); + // 0. Clean up existing memberships and notifications for rafi@student.com (user ID 1) + console.log('0. Cleaning up existing project memberships and notifications for rafi@student.com...'); await prisma.projectMember.deleteMany({ where: { id_user: 1 } }); + await prisma.notification.deleteMany({ + where: { id_user: 1 } + }); console.log(' Cleanup successful!\n'); let adminToken = '';