260322:1648 Correct Coresspondence / Doing RFA / Correct CI
CI Pipeline / build (push) Failing after 12m41s
Build and Deploy / deploy (push) Failing after 2m44s

This commit is contained in:
admin
2026-03-22 16:48:12 +07:00
parent e5deedb42e
commit 11984bfa29
683 changed files with 105251 additions and 29068 deletions
@@ -4,7 +4,7 @@ import {
IsOptional,
IsEnum,
IsNotEmpty,
IsUrl,
_IsUrl,
} from 'class-validator';
import { NotificationType } from '../entities/notification.entity';
@@ -17,7 +17,7 @@ export class SearchNotificationDto {
@Transform(({ value }) => {
if (value === 'true') return true;
if (value === 'false') return false;
return value;
return value as boolean | undefined;
})
isRead?: boolean; // กรอง: อ่านแล้ว/ยังไม่อ่าน
}
@@ -1,7 +1,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, LessThan } from 'typeorm';
import { Repository, _LessThan } from 'typeorm';
import { Notification } from './entities/notification.entity';
@Injectable()
@@ -20,6 +20,10 @@ interface NotificationPayload {
type: 'EMAIL' | 'LINE' | 'SYSTEM';
}
type NotificationJobData =
| NotificationPayload
| { userId: number; type: 'EMAIL' | 'LINE' };
@Processor('notifications')
export class NotificationProcessor extends WorkerHost {
private readonly logger = new Logger(NotificationProcessor.name);
@@ -37,28 +41,30 @@ export class NotificationProcessor extends WorkerHost {
super();
// Setup Nodemailer
this.mailerTransport = nodemailer.createTransport({
host: this.configService.get('SMTP_HOST'),
port: Number(this.configService.get('SMTP_PORT')),
secure: this.configService.get('SMTP_SECURE') === 'true',
host: this.configService.get<string>('SMTP_HOST'),
port: Number(this.configService.get<number>('SMTP_PORT')),
secure: this.configService.get<string>('SMTP_SECURE') === 'true',
auth: {
user: this.configService.get('SMTP_USER'),
pass: this.configService.get('SMTP_PASS'),
user: this.configService.get<string>('SMTP_USER'),
pass: this.configService.get<string>('SMTP_PASS'),
},
});
}
async process(job: Job<any, any, string>): Promise<any> {
async process(
job: Job<NotificationJobData, unknown, string>
): Promise<unknown> {
this.logger.debug(`Processing job ${job.name} (ID: ${job.id})`);
try {
switch (job.name) {
case 'dispatch-notification':
// Job หลัก: ตัดสินใจว่าจะส่งเลย หรือจะเข้า Digest Queue
return this.handleDispatch(job.data);
return this.handleDispatch(job.data as NotificationPayload);
case 'process-digest':
// Job รอง: ทำงานเมื่อครบเวลา Delay เพื่อส่งแบบรวม
return this.handleProcessDigest(job.data.userId, job.data.type);
case 'process-digest': {
const data = job.data as { userId: number; type: 'EMAIL' | 'LINE' };
return this.handleProcessDigest(data.userId, data.type);
}
default:
throw new Error(`Unknown job name: ${job.name}`);
@@ -152,8 +158,8 @@ export class NotificationProcessor extends WorkerHost {
if (!messagesRaw || messagesRaw.length === 0) return;
const messages: NotificationPayload[] = messagesRaw.map((m) =>
JSON.parse(m)
const messages: NotificationPayload[] = messagesRaw.map(
(m) => JSON.parse(m) as NotificationPayload
);
const user = await this.userService.findOne(userId);
@@ -206,7 +212,9 @@ export class NotificationProcessor extends WorkerHost {
}
private async sendLineImmediate(user: User, data: NotificationPayload) {
const n8nWebhookUrl = this.configService.get('N8N_LINE_WEBHOOK_URL');
const n8nWebhookUrl = this.configService.get<string>(
'N8N_LINE_WEBHOOK_URL'
);
if (!n8nWebhookUrl) return;
try {
@@ -223,7 +231,9 @@ export class NotificationProcessor extends WorkerHost {
}
private async sendLineDigest(user: User, messages: NotificationPayload[]) {
const n8nWebhookUrl = this.configService.get('N8N_LINE_WEBHOOK_URL');
const n8nWebhookUrl = this.configService.get<string>(
'N8N_LINE_WEBHOOK_URL'
);
if (!n8nWebhookUrl) return;
const summary = messages.map((m, i) => `${i + 1}. ${m.title}`).join('\n');
@@ -9,7 +9,7 @@ import { Repository } from 'typeorm';
// Entities
import { Notification, NotificationType } from './entities/notification.entity';
import { User } from '../user/entities/user.entity';
import { UserPreference } from '../user/entities/user-preference.entity';
import { _UserPreference } from '../user/entities/user-preference.entity';
// Gateway
import { NotificationGateway } from './notification.gateway';