@comasoft/nestjs 0.2.28 → 0.2.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/database/entities/notification.entity.d.ts +2 -1
- package/dist/database/entities/notification.entity.js +1 -1
- package/dist/events/services/event-notification.service.js +1 -1
- package/dist/notifications/index.d.ts +21 -7
- package/dist/notifications/services/email.service.d.ts +12 -6
- package/dist/notifications/services/email.service.js +1 -1
- package/dist/notifications/services/kakao.service.d.ts +4 -2
- package/dist/notifications/services/kakao.service.js +1 -1
- package/dist/notifications/services/notification-send.service.d.ts +3 -1
- package/dist/notifications/services/notification-send.service.js +1 -1
- package/dist/notifications/services/notification.service.d.ts +13 -10
- package/dist/notifications/services/notification.service.js +1 -1
- package/dist/notifications/services/sms.service.d.ts +4 -2
- package/dist/notifications/services/sms.service.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var t=this&&this.__decorate||function(t,e,o,n){var i,a=arguments.length,l=a<3?e:null===n?n=Object.getOwnPropertyDescriptor(e,o):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(t,e,o,n);else for(var p=t.length-1;p>=0;p--)(i=t[p])&&(l=(a<3?i(l):a>3?i(e,o,l):i(e,o))||l);return a>3&&l&&Object.defineProperty(e,o,l),l},e=this&&this.__metadata||function(t,e){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(t,e)};Object.defineProperty(exports,"__esModule",{value:!0}),exports.Notification=void 0;const o=require("typeorm"),n=require("../../enums.common");let i=class Notification{};exports.Notification=i,t([(0,o.PrimaryGeneratedColumn)({name:"id",primaryKeyConstraintName:"PK_notifications"}),e("design:type",Number)],i.prototype,"id",void 0),t([(0,o.Column)("varchar",{length:50,nullable:!0}),e("design:type",String)],i.prototype,"batch_id",void 0),t([(0,o.Column)("enum",{enum:n.NOTIFICATION_STATUS}),e("design:type",String)],i.prototype,"status",void 0),t([(0,o.Column)("varchar",{length:25,comment:Object.values(n.NOTIFICATION_TYPE).join(" | ")}),e("design:type",String)],i.prototype,"type",void 0),t([(0,o.Column)("varchar",{length:20,nullable:!0}),e("design:type",String)],i.prototype,"target_type",void 0),t([(0,o.Column)("int",{nullable:!0}),e("design:type",Number)],i.prototype,"target_id",void 0),t([(0,o.Column)("varchar",{length:100,nullable:!0}),e("design:type",String)],i.prototype,"recipient",void 0),t([(0,o.Column)("varchar",{length:50}),e("design:type",String)],i.prototype,"template_key",void 0),t([(0,o.Column)("varchar",{length:50,nullable:!0}),e("design:type",String)],i.prototype,"event_type",void 0),t([(0,o.Column)("int",{nullable:!0}),e("design:type",Number)],i.prototype,"event_id",void 0),t([(0,o.Column)("varchar",{length:100,nullable:!0}),e("design:type",String)],i.prototype,"title",void 0),t([(0,o.Column)("text",{nullable:!0}),e("design:type",String)],i.prototype,"content",void 0),t([(0,o.Column)("varchar",{length:50,nullable:!0}),e("design:type",String)],i.prototype,"sender",void 0),t([(0,o.Column)("jsonb",{nullable:!0}),e("design:type",Object)],i.prototype,"variables",void 0),t([(0,o.Column)("jsonb",{nullable:!0}),e("design:type",Object)],i.prototype,"meta",void 0),t([(0,o.Column)("timestamptz",{nullable:!0}),e("design:type",Date)],i.prototype,"scheduled_at",void 0),t([(0,o.Column)("timestamptz",{nullable:!0}),e("design:type",Date)],i.prototype,"sent_at",void 0),t([(0,o.Column)("timestamptz",{nullable:!0}),e("design:type",Date)],i.prototype,"read_at",void 0),t([(0,o.Column)("timestamptz",{nullable:!0}),e("design:type",Date)],i.prototype,"failed_at",void 0),t([(0,o.Column)("varchar",{length:255,nullable:!0}),e("design:type",String)],i.prototype,"reason_failed",void 0),t([(0,o.CreateDateColumn)({type:"timestamptz"}),e("design:type",Date)],i.prototype,"created_at",void 0),t([(0,o.UpdateDateColumn)({type:"timestamptz"}),e("design:type",Date)],i.prototype,"updated_at",void 0),t([(0,o.DeleteDateColumn)({type:"timestamptz"}),e("design:type",Date)],i.prototype,"deleted_at",void 0),exports.Notification=i=t([(0,o.Entity)("notifications"),(0,o.Index)("IDX_notifications_target",["target_type","target_id","created_at"]),(0,o.Index)("IDX_notifications_batch",["batch_id"]),(0,o.Index)("IDX_notifications_event",["event_type","event_id"])],i);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=this&&this.__decorate||function(e,t,i,n){var a,s=arguments.length,c=s<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)c=Reflect.decorate(e,t,i,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(c=(s<3?a(c):s>3?a(t,i,c):a(t,i))||c);return s>3&&c&&Object.defineProperty(t,i,c),c},t=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},i=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))(function(a,s){function fulfilled(e){try{step(n.next(e))}catch(e){s(e)}}function rejected(e){try{step(n.throw(e))}catch(e){s(e)}}function step(e){e.done?a(e.value):function adopt(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(fulfilled,rejected)}step((n=n.apply(e,t||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.EventNotificationService=void 0;const n=require("@nestjs/common"),a=require("../../notifications");let s=class EventNotificationService{constructor(e){this.notificationSendService=e}send(e){return i(this,void 0,void 0,function*(){const t=this.generateBatchId();return(null==e?void 0:e.in_app)&&(yield this.notificationSendService.send({batch_id:t,channels:["in_app"],recipients:e.in_app.recipients,title:e.in_app.title,content:e.in_app.content,template_key:e.in_app.template_key,variables:e.in_app.variables,event_type:e.in_app.event_type,event_id:e.in_app.event_id,meta:e.in_app.meta})),(null==e?void 0:e.mobile_push)&&(yield this.notificationSendService.send({batch_id:t,channels:["mobile_push"],recipients:e.mobile_push.recipients,title:e.mobile_push.title,content:e.mobile_push.content,template_key:e.mobile_push.template_key,variables:e.mobile_push.variables,meta:e.mobile_push.meta})),(null==e?void 0:e.web_push)&&(yield this.notificationSendService.send({batch_id:t,channels:["web_push"],recipients:e.web_push.recipients,title:e.web_push.title,content:e.web_push.content,template_key:e.web_push.template_key,variables:e.web_push.variables,meta:e.web_push.meta})),(null==e?void 0:e.email)&&(yield this.notificationSendService.send({batch_id:t,channels:["email"],recipients:e.email.recipients,title:e.email.subject,content:e.email.body,template_key:e.email.template_key,variables:e.email.variables})),(null==e?void 0:e.kakao)&&(yield this.notificationSendService.send({batch_id:t,channels:["kakao"],recipients:e.kakao.recipients,template_key:e.kakao.template_key,variables:e.kakao.variables})),(null==e?void 0:e.sms)&&(yield this.notificationSendService.send({batch_id:t,channels:["sms"],recipients:e.sms.recipients,content:e.sms.content,template_key:e.sms.template_key,variables:e.sms.variables})),(null==e?void 0:e.slack)&&(yield this.notificationSendService.send({batch_id:t,channels:["slack"],recipients:[{
|
|
1
|
+
var e=this&&this.__decorate||function(e,t,i,n){var a,s=arguments.length,c=s<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)c=Reflect.decorate(e,t,i,n);else for(var l=e.length-1;l>=0;l--)(a=e[l])&&(c=(s<3?a(c):s>3?a(t,i,c):a(t,i))||c);return s>3&&c&&Object.defineProperty(t,i,c),c},t=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},i=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))(function(a,s){function fulfilled(e){try{step(n.next(e))}catch(e){s(e)}}function rejected(e){try{step(n.throw(e))}catch(e){s(e)}}function step(e){e.done?a(e.value):function adopt(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(fulfilled,rejected)}step((n=n.apply(e,t||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.EventNotificationService=void 0;const n=require("@nestjs/common"),a=require("../../notifications");let s=class EventNotificationService{constructor(e){this.notificationSendService=e}send(e){return i(this,void 0,void 0,function*(){const t=this.generateBatchId();return(null==e?void 0:e.in_app)&&(yield this.notificationSendService.send({batch_id:t,channels:["in_app"],recipients:e.in_app.recipients,target_type:e.in_app.target_type,title:e.in_app.title,content:e.in_app.content,template_key:e.in_app.template_key,variables:e.in_app.variables,event_type:e.in_app.event_type,event_id:e.in_app.event_id,meta:e.in_app.meta})),(null==e?void 0:e.mobile_push)&&(yield this.notificationSendService.send({batch_id:t,channels:["mobile_push"],recipients:e.mobile_push.recipients,target_type:e.mobile_push.target_type,title:e.mobile_push.title,content:e.mobile_push.content,template_key:e.mobile_push.template_key,variables:e.mobile_push.variables,meta:e.mobile_push.meta})),(null==e?void 0:e.web_push)&&(yield this.notificationSendService.send({batch_id:t,channels:["web_push"],recipients:e.web_push.recipients,target_type:e.web_push.target_type,title:e.web_push.title,content:e.web_push.content,template_key:e.web_push.template_key,variables:e.web_push.variables,meta:e.web_push.meta})),(null==e?void 0:e.email)&&(yield this.notificationSendService.send({batch_id:t,channels:["email"],recipients:e.email.recipients,target_type:e.email.target_type,title:e.email.subject,content:e.email.body,template_key:e.email.template_key,variables:e.email.variables})),(null==e?void 0:e.kakao)&&(yield this.notificationSendService.send({batch_id:t,channels:["kakao"],recipients:e.kakao.recipients,target_type:e.kakao.target_type,template_key:e.kakao.template_key,variables:e.kakao.variables})),(null==e?void 0:e.sms)&&(yield this.notificationSendService.send({batch_id:t,channels:["sms"],recipients:e.sms.recipients,target_type:e.sms.target_type,content:e.sms.content,template_key:e.sms.template_key,variables:e.sms.variables})),(null==e?void 0:e.slack)&&(yield this.notificationSendService.send({batch_id:t,channels:["slack"],recipients:[{target_type:"system",target_id:0,recipient:e.slack.channel}],target_type:e.slack.target_type,content:e.slack.content,template_key:e.slack.template_key,variables:e.slack.variables})),{batch_id:t}})}generateBatchId(){return`BATCH_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}};exports.EventNotificationService=s,exports.EventNotificationService=s=e([(0,n.Injectable)(),t("design:paramtypes",[a.NotificationSendService])],s);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export * from './notification.module';
|
|
2
2
|
export * from './services';
|
|
3
3
|
export interface NotificationRecipient {
|
|
4
|
-
|
|
4
|
+
target_type: string;
|
|
5
|
+
target_id: number;
|
|
5
6
|
recipient: string;
|
|
6
7
|
variables?: Record<string, any>;
|
|
7
8
|
meta?: Record<string, any>;
|
|
@@ -9,6 +10,7 @@ export interface NotificationRecipient {
|
|
|
9
10
|
export interface NotificationOptions {
|
|
10
11
|
in_app?: {
|
|
11
12
|
recipients: NotificationRecipient[];
|
|
13
|
+
target_type: string;
|
|
12
14
|
title?: string;
|
|
13
15
|
content?: string;
|
|
14
16
|
template_key?: string;
|
|
@@ -19,6 +21,7 @@ export interface NotificationOptions {
|
|
|
19
21
|
};
|
|
20
22
|
mobile_push?: {
|
|
21
23
|
recipients: NotificationRecipient[];
|
|
24
|
+
target_type: string;
|
|
22
25
|
title?: string;
|
|
23
26
|
content?: string;
|
|
24
27
|
template_key?: string;
|
|
@@ -27,6 +30,7 @@ export interface NotificationOptions {
|
|
|
27
30
|
};
|
|
28
31
|
web_push?: {
|
|
29
32
|
recipients: NotificationRecipient[];
|
|
33
|
+
target_type: string;
|
|
30
34
|
title?: string;
|
|
31
35
|
content?: string;
|
|
32
36
|
template_key?: string;
|
|
@@ -35,12 +39,14 @@ export interface NotificationOptions {
|
|
|
35
39
|
};
|
|
36
40
|
email?: {
|
|
37
41
|
recipients: NotificationRecipient[];
|
|
42
|
+
target_type: string;
|
|
38
43
|
subject?: string;
|
|
39
44
|
body?: string;
|
|
40
45
|
template_key?: string;
|
|
41
46
|
variables?: Record<string, any>;
|
|
42
47
|
};
|
|
43
48
|
slack?: {
|
|
49
|
+
target_type: string;
|
|
44
50
|
channel: string;
|
|
45
51
|
content?: string;
|
|
46
52
|
template_key?: string;
|
|
@@ -48,11 +54,13 @@ export interface NotificationOptions {
|
|
|
48
54
|
};
|
|
49
55
|
kakao?: {
|
|
50
56
|
recipients: NotificationRecipient[];
|
|
57
|
+
target_type: string;
|
|
51
58
|
template_key: string;
|
|
52
59
|
variables?: Record<string, any>;
|
|
53
60
|
};
|
|
54
61
|
sms?: {
|
|
55
62
|
recipients: NotificationRecipient[];
|
|
63
|
+
target_type: string;
|
|
56
64
|
content?: string;
|
|
57
65
|
template_key?: string;
|
|
58
66
|
variables?: Record<string, any>;
|
|
@@ -62,7 +70,8 @@ export type NotificationPayload = {
|
|
|
62
70
|
type: 'in_app';
|
|
63
71
|
recipients: Array<{
|
|
64
72
|
recipient: string;
|
|
65
|
-
|
|
73
|
+
target_type: string;
|
|
74
|
+
target_id: number;
|
|
66
75
|
title?: string;
|
|
67
76
|
content?: string;
|
|
68
77
|
variables?: Record<string, any>;
|
|
@@ -79,7 +88,8 @@ export type NotificationPayload = {
|
|
|
79
88
|
type: 'mobile_push';
|
|
80
89
|
recipients: Array<{
|
|
81
90
|
recipient: string;
|
|
82
|
-
|
|
91
|
+
target_type: string;
|
|
92
|
+
target_id: number;
|
|
83
93
|
variables?: Record<string, any>;
|
|
84
94
|
}>;
|
|
85
95
|
title?: string;
|
|
@@ -91,7 +101,8 @@ export type NotificationPayload = {
|
|
|
91
101
|
type: 'web_push';
|
|
92
102
|
recipients: Array<{
|
|
93
103
|
recipient: string;
|
|
94
|
-
|
|
104
|
+
target_type: string;
|
|
105
|
+
target_id: number;
|
|
95
106
|
variables?: Record<string, any>;
|
|
96
107
|
}>;
|
|
97
108
|
title?: string;
|
|
@@ -103,7 +114,8 @@ export type NotificationPayload = {
|
|
|
103
114
|
type: 'email';
|
|
104
115
|
recipients: Array<{
|
|
105
116
|
recipient: string;
|
|
106
|
-
|
|
117
|
+
target_type: string;
|
|
118
|
+
target_id: number;
|
|
107
119
|
variables?: Record<string, any>;
|
|
108
120
|
}>;
|
|
109
121
|
subject?: string;
|
|
@@ -114,7 +126,8 @@ export type NotificationPayload = {
|
|
|
114
126
|
type: 'sms';
|
|
115
127
|
recipients: Array<{
|
|
116
128
|
recipient: string;
|
|
117
|
-
|
|
129
|
+
target_type: string;
|
|
130
|
+
target_id: number;
|
|
118
131
|
variables?: Record<string, any>;
|
|
119
132
|
}>;
|
|
120
133
|
content?: string;
|
|
@@ -124,7 +137,8 @@ export type NotificationPayload = {
|
|
|
124
137
|
type: 'kakao';
|
|
125
138
|
recipients: Array<{
|
|
126
139
|
recipient: string;
|
|
127
|
-
|
|
140
|
+
target_type: string;
|
|
141
|
+
target_id: number;
|
|
128
142
|
variables?: Record<string, any>;
|
|
129
143
|
}>;
|
|
130
144
|
template_key: string;
|
|
@@ -6,12 +6,14 @@ export declare class EmailService {
|
|
|
6
6
|
constructor(configService: ConfigService);
|
|
7
7
|
send(recipients: Array<{
|
|
8
8
|
recipient: string;
|
|
9
|
-
|
|
9
|
+
target_type?: string;
|
|
10
|
+
target_id?: number;
|
|
10
11
|
subject: string;
|
|
11
12
|
text: string;
|
|
12
13
|
variables?: Record<string, any>;
|
|
13
14
|
}>): Promise<{
|
|
14
|
-
|
|
15
|
+
target_type: string;
|
|
16
|
+
target_id: number;
|
|
15
17
|
recipient: string;
|
|
16
18
|
success: boolean;
|
|
17
19
|
content: string;
|
|
@@ -19,12 +21,14 @@ export declare class EmailService {
|
|
|
19
21
|
}[] | import("@aws-sdk/client-ses").SendEmailCommandOutput | import("resend").CreateEmailResponse>;
|
|
20
22
|
sendAws(recipients: Array<{
|
|
21
23
|
recipient: string;
|
|
22
|
-
|
|
24
|
+
target_type?: string;
|
|
25
|
+
target_id?: number;
|
|
23
26
|
subject: string;
|
|
24
27
|
text: string;
|
|
25
28
|
variables?: Record<string, any>;
|
|
26
29
|
}>): Promise<{
|
|
27
|
-
|
|
30
|
+
target_type: string;
|
|
31
|
+
target_id: number;
|
|
28
32
|
recipient: string;
|
|
29
33
|
success: boolean;
|
|
30
34
|
content: string;
|
|
@@ -32,12 +36,14 @@ export declare class EmailService {
|
|
|
32
36
|
}[] | import("@aws-sdk/client-ses").SendEmailCommandOutput>;
|
|
33
37
|
sendResend(recipients: Array<{
|
|
34
38
|
recipient: string;
|
|
35
|
-
|
|
39
|
+
target_type?: string;
|
|
40
|
+
target_id?: number;
|
|
36
41
|
subject: string;
|
|
37
42
|
text: string;
|
|
38
43
|
variables?: Record<string, any>;
|
|
39
44
|
}>): Promise<{
|
|
40
|
-
|
|
45
|
+
target_type: string;
|
|
46
|
+
target_id: number;
|
|
41
47
|
recipient: string;
|
|
42
48
|
success: boolean;
|
|
43
49
|
content: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=this&&this.__decorate||function(e,t,i,n){var s
|
|
1
|
+
var e=this&&this.__decorate||function(e,t,i,n){var r,s=arguments.length,c=s<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)c=Reflect.decorate(e,t,i,n);else for(var o=e.length-1;o>=0;o--)(r=e[o])&&(c=(s<3?r(c):s>3?r(t,i,c):r(t,i))||c);return s>3&&c&&Object.defineProperty(t,i,c),c},t=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},i=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))(function(r,s){function fulfilled(e){try{step(n.next(e))}catch(e){s(e)}}function rejected(e){try{step(n.throw(e))}catch(e){s(e)}}function step(e){e.done?r(e.value):function adopt(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(fulfilled,rejected)}step((n=n.apply(e,t||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.EmailService=void 0;const n=require("@aws-sdk/client-ses"),r=require("@nestjs/common"),s=require("@nestjs/config"),c=require("resend");let o=class EmailService{constructor(e){this.configService=e,"aws"===this.configService.get("EMAIL_PROVIDER")&&(this.sesClient=new n.SESClient({region:this.configService.get("AWS_REGION"),credentials:{accessKeyId:this.configService.get("AWS_ACCESS_KEY_ID"),secretAccessKey:this.configService.get("AWS_SECRET_ACCESS_KEY")}})),"resend"===this.configService.get("EMAIL_PROVIDER")&&(this.resendClient=new c.Resend(this.configService.get("RESEND_API_KEY")))}send(e){return i(this,void 0,void 0,function*(){const t=this.configService.get("EMAIL_PROVIDER");if(!t||!this.configService.get("EMAIL_FROM"))throw new Error("EMAIL_PROVIDER or EMAIL_FROM is not set");return"aws"===t?this.sendAws(e):"resend"===t?this.sendResend(e):[]})}sendAws(e){return i(this,void 0,void 0,function*(){if("production"!==process.env.NODE_ENV)return e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,success:!0,content:e.text,status:"sent"}));for(const t of e){const e=new n.SendEmailCommand({Source:this.configService.get("EMAIL_NOREPLY_SOURCE"),Destination:{ToAddresses:[t.recipient]},Message:{Subject:{Data:t.subject,Charset:"UTF-8"},Body:{Html:{Data:t.text,Charset:"UTF-8"}}}});return yield this.sesClient.send(e)}})}sendResend(e){return i(this,void 0,void 0,function*(){if("production"!==process.env.NODE_ENV)return console.log("📧 [EMAIL] Resend 배열 발송:",{count:e.length,from:this.configService.get("EMAIL_FROM"),provider:this.configService.get("EMAIL_PROVIDER"),recipients:e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,subject:e.subject,text:e.text.substring(0,50)+(e.text.length>50?"...":""),variables:e.variables})),timestamp:(new Date).toISOString()}),e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,success:!0,content:e.text,status:"sent"}));for(const t of e){return yield this.resendClient.emails.send({from:this.configService.get("EMAIL_NOREPLY_SOURCE"),to:[t.recipient],subject:t.subject,html:t.text})}})}};exports.EmailService=o,exports.EmailService=o=e([(0,r.Injectable)(),t("design:paramtypes",[s.ConfigService])],o);
|
|
@@ -2,7 +2,8 @@ import { ConfigService } from '@nestjs/config';
|
|
|
2
2
|
import { RedisService } from '../../redis';
|
|
3
3
|
interface KakaoMessage {
|
|
4
4
|
recipient: string;
|
|
5
|
-
|
|
5
|
+
target_type?: string;
|
|
6
|
+
target_id?: number;
|
|
6
7
|
sender_key?: string;
|
|
7
8
|
template_code?: string;
|
|
8
9
|
template_meta?: any;
|
|
@@ -14,7 +15,8 @@ export declare class KakaoService {
|
|
|
14
15
|
constructor(configService: ConfigService, redis: RedisService);
|
|
15
16
|
send(recipients: Array<KakaoMessage>): Promise<any[]>;
|
|
16
17
|
sendAligo(recipients: Array<KakaoMessage>): Promise<{
|
|
17
|
-
|
|
18
|
+
target_type: string;
|
|
19
|
+
target_id: number;
|
|
18
20
|
recipient: string;
|
|
19
21
|
success: boolean;
|
|
20
22
|
messageId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=this&&this.__decorate||function(e,t,i,
|
|
1
|
+
var e=this&&this.__decorate||function(e,t,i,r){var n,o=arguments.length,s=o<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,i,r);else for(var c=e.length-1;c>=0;c--)(n=e[c])&&(s=(o<3?n(s):o>3?n(t,i,s):n(t,i))||s);return o>3&&s&&Object.defineProperty(t,i,s),s},t=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},i=this&&this.__awaiter||function(e,t,i,r){return new(i||(i=Promise))(function(n,o){function fulfilled(e){try{step(r.next(e))}catch(e){o(e)}}function rejected(e){try{step(r.throw(e))}catch(e){o(e)}}function step(e){e.done?n(e.value):function adopt(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.KakaoService=void 0;const r=require("@nestjs/common"),n=require("@nestjs/config"),o=require("crypto"),s=require("../../redis");let c=class KakaoService{constructor(e,t){this.configService=e,this.redis=t}send(e){return i(this,void 0,void 0,function*(){const t=this.configService.get("KAKAO_PROVIDER");if(!t||!this.configService.get("KAKAO_FROM"))throw new Error("KAKAO_PROVIDER or KAKAO_FROM is not set");return"aligo"===t?this.sendAligo(e):"ppurio"===t?this.sendPpurio(e):"ncp"===t?this.sendNcp(e):[]})}sendAligo(e){return i(this,void 0,void 0,function*(){return console.log("📱 [KAKAO] Aligo 배열 발송:",{count:e.length,from:this.configService.get("KAKAO_FROM"),provider:"aligo",recipients:e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,template_code:e.template_code})),timestamp:(new Date).toISOString()}),e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,success:!0,messageId:`aligo-${Date.now()}-${e.target_id}`,status:"sent"}))})}getPpurioToken(){return i(this,void 0,void 0,function*(){if(yield this.redis.get("ppurio_token"))return yield this.redis.get("ppurio_token");const e=this.configService.get("PPURIO_ACCOUNT"),t=this.configService.get("PPURIO_PASSWORD"),i=btoa(`${e}:${t}`),r=yield fetch("https://api.bizppurio.com/v1/token",{method:"POST",headers:{"Content-Type":"application/json; charset=utf-8",Authorization:`Basic ${i}`},body:JSON.stringify({grant_type:"client_credentials"})}),n=yield r.json();if(n.accesstoken)return yield this.redis.set("ppurio_token",n.accesstoken,86e3),yield this.redis.get("ppurio_token");throw new Error(`cannot get ppurio access token: ${JSON.stringify(n)}`)})}sendPpurioMessage(e){return i(this,void 0,void 0,function*(){const t=e.recipient.trim().replace(/-/g,"");if(t.startsWith("0100")||11!==t.length)return;const i=yield this.getPpurioToken(),r=yield fetch("https://api.bizppurio.com/v3/message",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${i}`},body:JSON.stringify({account:this.configService.get("PPURIO_ACCOUNT"),refkey:this.configService.get("PPURIO_PASSWORD"),type:"at",from:this.configService.get("SMS_FROM"),to:e.recipient,content:{at:{senderkey:e.sender_key,templatecode:e.template_code,message:e.message}}})});return yield r.json()})}sendPpurio(e){return i(this,void 0,void 0,function*(){if("production"!==process.env.NODE_ENV)return console.log("📱 [KAKAO] Ppurio 발송:",{count:e.length,from:this.configService.get("KAKAO_FROM"),provider:"ppurio",recipients:e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,sender_key:e.sender_key,template_code:e.template_code,message:e.message})),timestamp:(new Date).toISOString()}),e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,success:!0,messageId:`ppurio-${Date.now()}-${e.target_id}`,message:e.message,status:"sent"}));return yield Promise.all(e.map(e=>this.sendPpurioMessage(e)))})}makeNcpSignature(e,t,i){const r=this.configService.get("NCP_ACCESS_KEY"),n=this.configService.get("NCP_SECRET_KEY"),s=`${e} ${t}\n${i}\n${r}`;return o.createHmac("sha256",n).update(s).digest("base64")}sendNcpMessage(e){return i(this,void 0,void 0,function*(){var t;const i=this.configService.get("NCP_SERVICE_ID"),r=this.configService.get("NCP_ACCESS_KEY");if(!i||!r)throw new Error("NCP_SERVICE_ID or NCP_ACCESS_KEY is not set");const n=Date.now().toString(),o=`/alimtalk/v2/services/${i}/messages`,s=this.makeNcpSignature("POST",o,n),c=e.recipient.trim().replace(/-/g,"");if(c.startsWith("0100")||11!==c.length)return;const a=yield fetch(`https://sens.apigw.ntruss.com${o}`,{method:"POST",headers:{"Content-Type":"application/json; charset=utf-8","x-ncp-apigw-timestamp":n,"x-ncp-iam-access-key":r,"x-ncp-apigw-signature-v2":s},body:JSON.stringify({plusFriendId:this.configService.get("KAKAO_FROM"),templateCode:e.template_code,messages:[Object.assign({countryCode:"82",to:c,content:e.message},null!==(t=e.template_meta)&&void 0!==t?t:{})]})});return yield a.json()})}sendNcp(e){return i(this,void 0,void 0,function*(){if("production"!==process.env.NODE_ENV)return console.log("📱 [KAKAO] NCP 발송:",JSON.stringify({count:e.length,recipients:e.map(e=>e),timestamp:(new Date).toISOString()},null,2)),e.map(e=>e);return yield Promise.all(e.map(e=>this.sendNcpMessage(e)))})}};exports.KakaoService=c,exports.KakaoService=c=e([(0,r.Injectable)(),t("design:paramtypes",[n.ConfigService,s.RedisService])],c);
|
|
@@ -7,11 +7,13 @@ import { SmsService } from './sms.service';
|
|
|
7
7
|
export interface SendNotificationDto {
|
|
8
8
|
batch_id?: string;
|
|
9
9
|
recipients: Array<{
|
|
10
|
-
|
|
10
|
+
target_type: string;
|
|
11
|
+
target_id: number;
|
|
11
12
|
recipient?: string;
|
|
12
13
|
variables?: Record<string, any>;
|
|
13
14
|
}>;
|
|
14
15
|
channels: Array<'in_app' | 'mobile_push' | 'web_push' | 'email' | 'sms' | 'kakao' | 'slack'>;
|
|
16
|
+
target_type: string;
|
|
15
17
|
template_key?: string;
|
|
16
18
|
title?: string;
|
|
17
19
|
content?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e,t=this&&this.__decorate||function(e,t,i,n){var r,
|
|
1
|
+
var e,t=this&&this.__decorate||function(e,t,i,n){var r,a=arguments.length,s=a<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,i,n);else for(var o=e.length-1;o>=0;o--)(r=e[o])&&(s=(a<3?r(s):a>3?r(t,i,s):r(t,i))||s);return a>3&&s&&Object.defineProperty(t,i,s),s},i=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},n=this&&this.__awaiter||function(e,t,i,n){return new(i||(i=Promise))(function(r,a){function fulfilled(e){try{step(n.next(e))}catch(e){a(e)}}function rejected(e){try{step(n.throw(e))}catch(e){a(e)}}function step(e){e.done?r(e.value):function adopt(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(fulfilled,rejected)}step((n=n.apply(e,t||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.NotificationSendService=void 0;const r=require("@nestjs/common"),a=require("../../enums.common"),s=require("./email.service"),o=require("./kakao.service"),c=require("./message-template.service"),l=require("./notification.service"),p=require("./slack.service"),d=require("./sms.service");let h=e=class NotificationSendService{constructor(t,i,n,a,s,o){this.notificationService=t,this.emailService=i,this.smsService=n,this.kakaoService=a,this.slackService=s,this.templateService=o,this.logger=new r.Logger(e.name)}send(e){return n(this,void 0,void 0,function*(){const{title:t,content:i,template_code:n,template_meta:r}=yield this.renderTemplate(e);return 1===e.recipients.length?yield this.sendSingle(e,t,i,n,r):(this.logger.log(`1:N 배치 알림 발송 시작: ${t} (${e.recipients.length}명)`),yield this.sendBatch(e,t,i,n,r))})}sendSingle(e,t,i,r,s){return n(this,void 0,void 0,function*(){const n=e.recipients[0],o=[];for(const c of e.channels){let l;try{"in_app"===c?(l=yield this.notificationService.createSingle({target_type:e.target_type,target_id:n.target_id,recipient:n.recipient,type:"in_app",template_key:e.template_key,event_type:e.event_type,event_id:e.event_id,title:t,content:i,variables:Object.assign(Object.assign({},e.variables),n.variables),meta:Object.assign(Object.assign({},e.meta),{template_code:r||"",template_meta:s||{}})}),l.status=a.NOTIFICATION_STATUS.SENT,l.sent_at=new Date,yield this.notificationService.notificationRepository.save(l)):(l=yield this.notificationService.createSingle({target_type:e.target_type,target_id:n.target_id,recipient:n.recipient,type:c,template_key:e.template_key,event_type:e.event_type,event_id:e.event_id,title:t,content:i,variables:Object.assign(Object.assign({},e.variables),n.variables),meta:Object.assign({},e.meta)}),yield this.sendToChannel(c,{recipient:n.recipient,title:t,content:i,target_type:e.target_type,target_id:n.target_id,template_code:r,template_meta:s,meta:e.meta}),l.status=a.NOTIFICATION_STATUS.SENT,l.sent_at=new Date,yield this.notificationService.notificationRepository.save(l),this.logger.log(`${c} 발송 성공: target_type=${e.target_type}, target_id=${n.target_id}`)),o.push({channel:c,status:"success",notification:l})}catch(e){this.logger.error(`${c} 발송 실패: ${e.message}`,e.stack),l&&(l.status=a.NOTIFICATION_STATUS.FAILED,l.failed_at=new Date,l.reason_failed=e.message,yield this.notificationService.notificationRepository.save(l)),o.push({channel:c,status:"failed",error:e.message})}}return o})}sendBatch(e,t,i,r,s){return n(this,void 0,void 0,function*(){const{batch_id:n,total_count:r}=yield this.notificationService.createBatch({batch_id:e.batch_id,recipients:e.recipients,type:"in_app",template_key:e.template_key,event_type:e.event_type,event_id:e.event_id,title:e.title,content:e.content,variables:e.variables,meta:e.meta,channels:e.channels});this.logger.log(`배치 생성 완료: ${n} (${r}건)`);const s=e.channels.filter(e=>"in_app"!==e),o=[];for(const r of s)try{yield this.sendBatchToChannel(r,{recipients:e.recipients,title:t,content:i,meta:e.meta}),yield this.notificationService.notificationRepository.update({batch_id:n,type:r},{status:a.NOTIFICATION_STATUS.SENT,sent_at:new Date}),o.push({channel:r,status:"sent"}),this.logger.log(`${r} 배치 발송 성공: ${e.recipients.length}건`)}catch(e){this.logger.error(`${r} 배치 발송 실패: ${e.message}`,e.stack),yield this.notificationService.notificationRepository.update({batch_id:n,type:r},{status:a.NOTIFICATION_STATUS.FAILED,failed_at:new Date,reason_failed:e.message}),o.push({channel:r,status:"failed",error:e.message})}return{batch_id:n,total_count:r,send_results:o}})}sendToChannel(e,t){return n(this,void 0,void 0,function*(){switch(e){case"mobile_push":throw this.logger.warn("mobile_push 채널은 아직 구현되지 않았습니다"),new Error("mobile_push not implemented yet");case"web_push":throw this.logger.warn("web_push 채널은 아직 구현되지 않았습니다"),new Error("web_push not implemented yet");case"email":return yield this.emailService.send([{recipient:t.recipient,target_type:t.target_type,target_id:t.target_id,subject:t.title,text:t.content}]);case"sms":return yield this.smsService.send([{recipient:t.recipient,target_type:t.target_type,target_id:t.target_id,message:t.content}]);case"kakao":return yield this.kakaoService.send([{recipient:t.recipient,target_type:t.target_type,target_id:t.target_id,sender_key:t.sender_key,template_code:t.template_code,template_meta:t.template_meta,message:t.content}]);case"slack":return yield this.slackService.send(t.recipient,t.content);default:throw new Error(`Unknown channel: ${e}`)}})}sendBatchToChannel(e,t){return n(this,void 0,void 0,function*(){switch(e){case"mobile_push":throw this.logger.warn("mobile_push 배치 발송은 아직 구현되지 않았습니다"),new Error("mobile_push batch sending not implemented yet");case"web_push":throw this.logger.warn("web_push 배치 발송은 아직 구현되지 않았습니다"),new Error("web_push batch sending not implemented yet");case"email":{const e=t.recipients.map(e=>({recipient:e.recipient,target_type:e.target_type,target_id:e.target_id,subject:t.title,text:t.content})).filter(e=>e.recipient);if(0===e.length)throw new Error("No email addresses provided");return yield this.emailService.send(e)}case"sms":{const e=t.recipients.map(e=>({recipient:e.recipient,target_type:e.target_type,target_id:e.target_id,message:t.content})).filter(e=>e.recipient);if(0===e.length)throw new Error("No phone numbers provided");return yield this.smsService.send(e)}case"kakao":{const e=t.recipients.map(e=>{var i,n;return{recipient:e.recipient,target_type:e.target_type,target_id:e.target_id,sender_key:null===(i=t.meta)||void 0===i?void 0:i.sender_key,template_code:null===(n=t.meta)||void 0===n?void 0:n.template_code,message:t.content}}).filter(e=>e.recipient);if(0===e.length)throw new Error("No kakao recipients provided");return yield this.kakaoService.send(e)}default:throw new Error(`Batch sending not supported for ${e}`)}})}resendBatch(e,t){return n(this,void 0,void 0,function*(){this.logger.log(`배치 재발송 시작: ${e}, ${t}`);const i=yield this.notificationService.notificationRepository.find({where:{batch_id:e,type:t}});if(0===i.length)throw new Error(`Batch records not found: ${e}, ${t}`);const n=i.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,variables:e.variables})),r=i[0];try{return yield this.sendBatchToChannel(t,{recipients:n,title:r.title,content:r.content,meta:r.meta}),yield this.notificationService.notificationRepository.update({batch_id:e,type:t},{status:a.NOTIFICATION_STATUS.SENT,sent_at:new Date}),this.logger.log(`배치 재발송 성공: ${e}`),{success:!0,batch_id:e,channel:t,count:n.length}}catch(i){throw this.logger.error(`배치 재발송 실패: ${i.message}`,i.stack),yield this.notificationService.notificationRepository.update({batch_id:e,type:t},{status:a.NOTIFICATION_STATUS.FAILED,failed_at:new Date,reason_failed:i.message}),i}})}renderTemplate(e){return n(this,void 0,void 0,function*(){var t;if(e.template_key){const i=e.channels[0],n=yield this.templateService.getTemplate(i,e.template_key);if(!n)throw new Error(`Template not found: ${e.template_key} for ${i}`);const r=Object.assign(Object.assign({},e.variables),(null===(t=e.recipients[0])||void 0===t?void 0:t.variables)||{}),a=this.templateService.renderTemplate(n,r);return{title:a.title||e.title||"",content:a.content,template_code:n.template_code,template_meta:n.template_meta}}if(!e.title||!e.content)throw new Error("title and content are required when template_key is not provided");return{title:e.title,content:e.content}})}};exports.NotificationSendService=h,exports.NotificationSendService=h=e=t([(0,r.Injectable)(),i("design:paramtypes",[l.NotificationService,s.EmailService,d.SmsService,o.KakaoService,p.SlackService,c.MessageTemplateService])],h);
|
|
@@ -4,8 +4,9 @@ import { NOTIFICATION_STATUS } from '../../enums.common';
|
|
|
4
4
|
export declare class NotificationService {
|
|
5
5
|
readonly notificationRepository: Repository<Notification>;
|
|
6
6
|
constructor(notificationRepository: Repository<Notification>);
|
|
7
|
-
createSingle({
|
|
8
|
-
|
|
7
|
+
createSingle({ target_type, target_id, recipient, type, template_key, event_type, event_id, title, content, variables, meta, }: {
|
|
8
|
+
target_type: string;
|
|
9
|
+
target_id: number;
|
|
9
10
|
recipient?: string;
|
|
10
11
|
type: string;
|
|
11
12
|
template_key: string;
|
|
@@ -16,7 +17,8 @@ export declare class NotificationService {
|
|
|
16
17
|
variables?: Record<string, any>;
|
|
17
18
|
meta?: Record<string, any>;
|
|
18
19
|
}): Promise<{
|
|
19
|
-
|
|
20
|
+
target_type: string;
|
|
21
|
+
target_id: number;
|
|
20
22
|
recipient: string;
|
|
21
23
|
type: any;
|
|
22
24
|
template_key: string;
|
|
@@ -31,7 +33,8 @@ export declare class NotificationService {
|
|
|
31
33
|
createBatch({ batch_id, recipients, type, template_key, event_type, event_id, title, content, variables, meta, channels, }: {
|
|
32
34
|
batch_id?: string;
|
|
33
35
|
recipients: Array<{
|
|
34
|
-
|
|
36
|
+
target_type: string;
|
|
37
|
+
target_id: number;
|
|
35
38
|
recipient?: string;
|
|
36
39
|
variables?: Record<string, any>;
|
|
37
40
|
}>;
|
|
@@ -49,18 +52,18 @@ export declare class NotificationService {
|
|
|
49
52
|
total_count: number;
|
|
50
53
|
notifications: any[];
|
|
51
54
|
}>;
|
|
52
|
-
|
|
55
|
+
findByTarget(target_type: string, target_id: number, options?: {
|
|
53
56
|
limit?: number;
|
|
54
57
|
offset?: number;
|
|
55
58
|
unread_only?: boolean;
|
|
56
59
|
}): Promise<Notification[]>;
|
|
57
|
-
countUnread(
|
|
58
|
-
markAsRead(id: number,
|
|
59
|
-
markAllAsRead(
|
|
60
|
-
delete(id: number,
|
|
60
|
+
countUnread(target_type: string, target_id: number): Promise<number>;
|
|
61
|
+
markAsRead(id: number, target_type: string, target_id: number): Promise<import("typeorm").UpdateResult>;
|
|
62
|
+
markAllAsRead(target_type: string, target_id: number): Promise<import("typeorm").UpdateResult>;
|
|
63
|
+
delete(id: number, target_type: string, target_id: number): Promise<import("typeorm").UpdateResult>;
|
|
61
64
|
markBatchAsSent(batch_id: string, channel: string): Promise<import("typeorm").UpdateResult>;
|
|
62
65
|
markBatchAsFailed(batch_id: string, channel: string, reason: string): Promise<import("typeorm").UpdateResult>;
|
|
63
|
-
|
|
66
|
+
findBatchRecords(batch_id: string, channel: string): Promise<Notification>;
|
|
64
67
|
findBatchRecipients(batch_id: string): Promise<Notification[]>;
|
|
65
68
|
getBatchStats(batch_id: string): Promise<{
|
|
66
69
|
total: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var t=this&&this.__decorate||function(t,e,i,n){var r
|
|
1
|
+
var t=this&&this.__decorate||function(t,e,i,n){var a,r=arguments.length,o=r<3?e:null===n?n=Object.getOwnPropertyDescriptor(e,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(t,e,i,n);else for(var d=t.length-1;d>=0;d--)(a=t[d])&&(o=(r<3?a(o):r>3?a(e,i,o):a(e,i))||o);return r>3&&o&&Object.defineProperty(e,i,o),o},e=this&&this.__metadata||function(t,e){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(t,e)},i=this&&this.__param||function(t,e){return function(i,n){e(i,n,t)}},n=this&&this.__awaiter||function(t,e,i,n){return new(i||(i=Promise))(function(a,r){function fulfilled(t){try{step(n.next(t))}catch(t){r(t)}}function rejected(t){try{step(n.throw(t))}catch(t){r(t)}}function step(t){t.done?a(t.value):function adopt(t){return t instanceof i?t:new i(function(e){e(t)})}(t.value).then(fulfilled,rejected)}step((n=n.apply(t,e||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.NotificationService=void 0;const a=require("@nestjs/common"),r=require("@nestjs/typeorm"),o=require("typeorm"),d=require("../../database/entities"),s=require("../../enums.common");let c=class NotificationService{constructor(t){this.notificationRepository=t}createSingle(t){return n(this,arguments,void 0,function*({target_type:t,target_id:e,recipient:i,type:n,template_key:a,event_type:r,event_id:o,title:d,content:c,variables:p,meta:u}){return yield this.notificationRepository.save({target_type:t,target_id:e,recipient:i,type:n,template_key:a,event_type:r,event_id:o,title:d,content:c,variables:p,meta:u,status:s.NOTIFICATION_STATUS.PENDING})})}createBatch(t){return n(this,arguments,void 0,function*({batch_id:t,recipients:e,type:i,template_key:n,event_type:a,event_id:r,title:o,content:d,variables:c,meta:p,channels:u=["in_app","mobile_push"]}){const _=t||this.generateBatchId(),l=[];for(const t of u){const i=e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,type:t,template_key:n,event_type:a,event_id:r,title:o,content:d,variables:Object.assign(Object.assign({},c),e.variables),meta:p,batch_id:_,status:"in_app"===t?s.NOTIFICATION_STATUS.SENT:s.NOTIFICATION_STATUS.PENDING,sent_at:"in_app"===t?new Date:null}));l.push(...i)}const y=yield this.notificationRepository.save(l);return{batch_id:_,total_count:y.length,notifications:y}})}findByTarget(t,e,i){return n(this,void 0,void 0,function*(){const n=this.notificationRepository.createQueryBuilder("n").where("n.target_type = :target_type",{target_type:t}).andWhere("n.target_id = :target_id",{target_id:e}).andWhere("n.type = :type",{type:"in_app"}).andWhere("n.deleted_at IS NULL");return(null==i?void 0:i.unread_only)&&n.andWhere("n.read_at IS NULL"),n.orderBy("n.created_at","DESC").limit((null==i?void 0:i.limit)||20).offset((null==i?void 0:i.offset)||0),yield n.getMany()})}countUnread(t,e){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.count({where:{target_type:t,target_id:e,type:"in_app",read_at:(0,o.IsNull)(),deleted_at:(0,o.IsNull)()}})})}markAsRead(t,e,i){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.update({id:t,target_type:e,target_id:i,type:"in_app"},{status:s.NOTIFICATION_STATUS.READ,read_at:new Date})})}markAllAsRead(t,e){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.update({target_type:t,target_id:e,type:"in_app",read_at:(0,o.IsNull)()},{status:s.NOTIFICATION_STATUS.READ,read_at:new Date})})}delete(t,e,i){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.softDelete({id:t,target_type:e,target_id:i,type:"in_app"})})}markBatchAsSent(t,e){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.update({batch_id:t,type:e},{status:s.NOTIFICATION_STATUS.SENT,sent_at:new Date})})}markBatchAsFailed(t,e,i){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.update({batch_id:t,type:e},{status:s.NOTIFICATION_STATUS.FAILED,failed_at:new Date,reason_failed:i})})}findBatchRecords(t,e){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.findOne({where:{batch_id:t,type:e}})})}findBatchRecipients(t){return n(this,void 0,void 0,function*(){return yield this.notificationRepository.find({where:{batch_id:t,type:"in_app"},order:{created_at:"DESC"}})})}getBatchStats(t){return n(this,void 0,void 0,function*(){const e=yield this.notificationRepository.createQueryBuilder("n").select("COUNT(*)","total").addSelect("COUNT(n.read_at)","read").addSelect("COUNT(*) - COUNT(n.read_at)","unread").addSelect("ROUND(COUNT(n.read_at) * 100.0 / COUNT(*), 2)","read_rate").where("n.batch_id = :batch_id",{batch_id:t}).andWhere("n.type = :type",{type:"in_app"}).getRawOne();return{total:parseInt(e.total),read:parseInt(e.read),unread:parseInt(e.unread),read_rate:parseFloat(e.read_rate)}})}generateBatchId(){return`BATCH_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}};exports.NotificationService=c,exports.NotificationService=c=t([(0,a.Injectable)(),i(0,(0,r.InjectRepository)(d.Notification)),e("design:paramtypes",[o.Repository])],c);
|
|
@@ -6,11 +6,13 @@ export declare class SmsService {
|
|
|
6
6
|
constructor(configService: ConfigService, notificationService: NotificationService);
|
|
7
7
|
send(recipients: Array<{
|
|
8
8
|
recipient: string;
|
|
9
|
-
|
|
9
|
+
target_type?: string;
|
|
10
|
+
target_id?: number;
|
|
10
11
|
message: string;
|
|
11
12
|
variables?: Record<string, any>;
|
|
12
13
|
}>): Promise<{
|
|
13
|
-
|
|
14
|
+
target_type: string;
|
|
15
|
+
target_id: number;
|
|
14
16
|
recipient: string;
|
|
15
17
|
success: boolean;
|
|
16
18
|
messageId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=this&&this.__decorate||function(e,t,i,r){var n,c=arguments.length,o=c<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var s=e.length-1;s>=0;s--)(n=e[s])&&(o=(c<3?n(o):c>3?n(t,i,o):n(t,i))||o);return c>3&&o&&Object.defineProperty(t,i,o),o},t=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},i=this&&this.__awaiter||function(e,t,i,r){return new(i||(i=Promise))(function(n,c){function fulfilled(e){try{step(r.next(e))}catch(e){c(e)}}function rejected(e){try{step(r.throw(e))}catch(e){c(e)}}function step(e){e.done?n(e.value):function adopt(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.SmsService=void 0;const r=require("@nestjs/common"),n=require("@nestjs/config"),c=require("./notification.service");let o=class SmsService{constructor(e,t){this.configService=e,this.notificationService=t}send(e){return i(this,void 0,void 0,function*(){if(!this.configService.get("SMS_FROM"))throw new Error("SMS_FROM is not set");return console.log("📱 [SMS] 배열 발송:",{count:e.length,from:this.configService.get("SMS_FROM"),provider:this.configService.get("SMS_PROVIDER")||"default",recipients:e.map(e=>({
|
|
1
|
+
var e=this&&this.__decorate||function(e,t,i,r){var n,c=arguments.length,o=c<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,r);else for(var s=e.length-1;s>=0;s--)(n=e[s])&&(o=(c<3?n(o):c>3?n(t,i,o):n(t,i))||o);return c>3&&o&&Object.defineProperty(t,i,o),o},t=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)},i=this&&this.__awaiter||function(e,t,i,r){return new(i||(i=Promise))(function(n,c){function fulfilled(e){try{step(r.next(e))}catch(e){c(e)}}function rejected(e){try{step(r.throw(e))}catch(e){c(e)}}function step(e){e.done?n(e.value):function adopt(e){return e instanceof i?e:new i(function(t){t(e)})}(e.value).then(fulfilled,rejected)}step((r=r.apply(e,t||[])).next())})};Object.defineProperty(exports,"__esModule",{value:!0}),exports.SmsService=void 0;const r=require("@nestjs/common"),n=require("@nestjs/config"),c=require("./notification.service");let o=class SmsService{constructor(e,t){this.configService=e,this.notificationService=t}send(e){return i(this,void 0,void 0,function*(){if(!this.configService.get("SMS_FROM"))throw new Error("SMS_FROM is not set");return console.log("📱 [SMS] 배열 발송:",{count:e.length,from:this.configService.get("SMS_FROM"),provider:this.configService.get("SMS_PROVIDER")||"default",recipients:e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,message:e.message,variables:e.variables})),timestamp:(new Date).toISOString()}),e.map(e=>({target_type:e.target_type,target_id:e.target_id,recipient:e.recipient,success:!0,messageId:`sms-${Date.now()}-${e.target_id}`,status:"sent"}))})}};exports.SmsService=o,exports.SmsService=o=e([(0,r.Injectable)(),t("design:paramtypes",[n.ConfigService,c.NotificationService])],o);
|