251208:0010 Backend & Frontend Debug
Spec Validation / validate-markdown (push) Has been cancelled
Spec Validation / validate-diagrams (push) Has been cancelled
Spec Validation / check-todos (push) Has been cancelled

This commit is contained in:
2025-12-08 00:10:37 +07:00
parent 32d820ea6b
commit dcd126d704
99 changed files with 2775 additions and 1480 deletions
@@ -58,6 +58,13 @@ export class NotificationController {
return { data: items, meta: { total, page, limit, unreadCount } };
}
@Get('unread')
@ApiOperation({ summary: 'Get unread notification count' })
async getUnreadCount(@CurrentUser() user: User) {
const count = await this.notificationService.getUnreadCount(user.user_id);
return { unreadCount: count };
}
@Put(':id/read')
@ApiOperation({ summary: 'Mark notification as read' })
async markAsRead(
@@ -31,7 +31,7 @@ export class NotificationProcessor extends WorkerHost {
private configService: ConfigService,
private userService: UserService,
@InjectQueue('notifications') private notificationQueue: Queue,
@InjectRedis() private readonly redis: Redis,
@InjectRedis() private readonly redis: Redis
) {
super();
// Setup Nodemailer
@@ -66,7 +66,7 @@ export class NotificationProcessor extends WorkerHost {
// ✅ แก้ไขตรงนี้: Type Casting (error as Error)
this.logger.error(
`Failed to process job ${job.name}: ${(error as Error).message}`,
(error as Error).stack,
(error as Error).stack
);
throw error; // ให้ BullMQ จัดการ Retry
}
@@ -85,7 +85,7 @@ export class NotificationProcessor extends WorkerHost {
return;
}
const prefs = user.preferences || {
const prefs = user.preference || {
notify_email: true,
notify_line: true,
digest_mode: false,
@@ -126,13 +126,13 @@ export class NotificationProcessor extends WorkerHost {
{
delay: this.DIGEST_DELAY,
jobId: `digest-${data.type}-${data.userId}-${Date.now()}`,
},
}
);
// Set Lock ไว้ตามเวลา Delay เพื่อไม่ให้สร้าง Job ซ้ำ
await this.redis.set(lockKey, '1', 'PX', this.DIGEST_DELAY);
this.logger.log(
`Scheduled digest for User ${data.userId} (${data.type}) in ${this.DIGEST_DELAY}ms`,
`Scheduled digest for User ${data.userId} (${data.type}) in ${this.DIGEST_DELAY}ms`
);
}
}
@@ -152,7 +152,7 @@ export class NotificationProcessor extends WorkerHost {
if (!messagesRaw || messagesRaw.length === 0) return;
const messages: NotificationPayload[] = messagesRaw.map((m) =>
JSON.parse(m),
JSON.parse(m)
);
const user = await this.userService.findOne(userId);
@@ -185,7 +185,7 @@ export class NotificationProcessor extends WorkerHost {
const listItems = messages
.map(
(msg) =>
`<li><strong>${msg.title}</strong>: ${msg.message} <a href="${msg.link}">[View]</a></li>`,
`<li><strong>${msg.title}</strong>: ${msg.message} <a href="${msg.link}">[View]</a></li>`
)
.join('');
@@ -200,7 +200,7 @@ export class NotificationProcessor extends WorkerHost {
`,
});
this.logger.log(
`Digest Email sent to ${user.email} (${messages.length} items)`,
`Digest Email sent to ${user.email} (${messages.length} items)`
);
}
@@ -130,6 +130,15 @@ export class NotificationService {
};
}
/**
* ดึงจำนวน Notification ที่ยังไม่ได้อ่าน
*/
async getUnreadCount(userId: number): Promise<number> {
return this.notificationRepo.count({
where: { userId, isRead: false },
});
}
async markAsRead(id: number, userId: number): Promise<void> {
const notification = await this.notificationRepo.findOne({
where: { id, userId },