Skip to content

Commit 6848289

Browse files
authored
Merge pull request #60 from wileyday/master
RCS 발송 추가
2 parents 9c1e824 + 5227646 commit 6848289

6 files changed

Lines changed: 247 additions & 3 deletions

File tree

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/**
2+
* RCS 문자 발송 예제
3+
* 발신번호, 수신번호에 반드시 -, * 등 특수문자를 제거하여 기입하시기 바랍니다. 예) 01012345678
4+
*/
5+
const {SolapiMessageService} = require('solapi');
6+
const messageService = new SolapiMessageService(
7+
'ENTER_YOUR_API_KEY',
8+
'ENTER_YOUR_API_SECRET',
9+
);
10+
11+
// 단일 발송 예제, send 메소드로도 동일하게 사용가능
12+
messageService
13+
.sendOne({
14+
to: '수신번호',
15+
from: '계정에서 등록한 RCS용 발신번호 입력',
16+
text: '한글 45자, 영자 90자 이하 입력되면 자동으로 SMS타입의 메시지가 발송됩니다.',
17+
rcsOptions: {
18+
brandId: 'RCS 브랜드의 아이디',
19+
buttons: [
20+
{
21+
buttonType: 'WL',
22+
buttonName: '웹링크 버튼',
23+
link: 'https://으로 시작하는 웹링크 주소',
24+
}
25+
],
26+
},
27+
})
28+
.then(res => console.log(res));
29+
30+
// 단일 예약발송 예제, send 메소드로도 동일하게 사용가능
31+
// 예약발송 시 현재 시간보다 과거의 시간을 입력할 경우 즉시 발송됩니다.
32+
messageService
33+
.sendOneFuture(
34+
{
35+
to: '수신번호',
36+
from: '계정에서 등록한 RCS용 발신번호 입력',
37+
text: '한글 45자, 영자 90자 이하 입력되면 자동으로 SMS타입의 메시지가 발송됩니다.',
38+
rcsOptions: {
39+
brandId: 'RCS 브랜드의 아이디',
40+
buttons: [
41+
{
42+
buttonType: 'WL',
43+
buttonName: '웹링크 버튼',
44+
link: 'https://으로 시작하는 웹링크 주소',
45+
}
46+
],
47+
},
48+
},
49+
'2022-12-08 00:00:00',
50+
)
51+
.then(res => console.log(res));
52+
53+
// 여러 메시지 발송 예제, 한 번 호출 당 최대 10,000건 까지 발송 가능
54+
messageService
55+
.send([
56+
{
57+
to: '수신번호',
58+
from: '계정에서 등록한 RCS용 발신번호 입력',
59+
text: '한글 45자, 영자 90자 이하 입력되면 자동으로 SMS타입의 메시지가 발송됩니다.',
60+
rcsOptions: {
61+
brandId: 'RCS 브랜드의 아이디',
62+
buttons: [
63+
{
64+
buttonType: 'WL',
65+
buttonName: '웹링크 버튼',
66+
link: 'https://으로 시작하는 웹링크 주소',
67+
}
68+
],
69+
},
70+
},
71+
{
72+
to: '수신번호',
73+
from: '계정에서 등록한 RCS용 발신번호 입력',
74+
text: '한글 45자, 영자 90자 이하 입력되면 자동으로 SMS타입의 메시지가 발송됩니다.',
75+
rcsOptions: {
76+
brandId: 'RCS 브랜드의 아이디',
77+
buttons: [
78+
{
79+
buttonType: 'WL',
80+
buttonName: '웹링크 버튼',
81+
link: 'https://으로 시작하는 웹링크 주소',
82+
}
83+
],
84+
},
85+
},
86+
// 2번째 파라미터 내 항목인 allowDuplicates 옵션을 true로 설정할 경우 중복 수신번호를 허용합니다.
87+
])
88+
.then(res => console.log(res));
89+
90+
// 여러 메시지 예약발송 예제, 한 번 호출 당 최대 10,000건 까지 발송 가능
91+
// 예약발송 시 현재 시간보다 과거의 시간을 입력할 경우 즉시 발송됩니다.
92+
messageService
93+
.send(
94+
[
95+
{
96+
to: '수신번호',
97+
from: '계정에서 등록한 RCS용 발신번호 입력',
98+
text: '한글 45자, 영자 90자 이하 입력되면 자동으로 SMS타입의 메시지가 발송됩니다.',
99+
rcsOptions: {
100+
brandId: 'RCS 브랜드의 아이디',
101+
buttons: [
102+
{
103+
buttonType: 'WL',
104+
buttonName: '웹링크 버튼',
105+
link: 'https://으로 시작하는 웹링크 주소',
106+
}
107+
],
108+
},
109+
},
110+
{
111+
to: '수신번호',
112+
from: '계정에서 등록한 RCS용 발신번호 입력',
113+
text: '한글 45자, 영자 90자 이하 입력되면 자동으로 SMS타입의 메시지가 발송됩니다.',
114+
rcsOptions: {
115+
brandId: 'RCS 브랜드의 아이디',
116+
buttons: [
117+
{
118+
buttonType: 'WL',
119+
buttonName: '웹링크 버튼',
120+
link: 'https://으로 시작하는 웹링크 주소',
121+
}
122+
],
123+
},
124+
},
125+
],
126+
{
127+
scheduledDate: '2022-12-08 00:00:00',
128+
// allowDuplicates 옵션을 true로 설정할 경우 중복 수신번호를 허용합니다.
129+
// allowDuplicates: true,
130+
},
131+
)
132+
.then(res => console.log(res));

examples/javascript/webhooks/index.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,28 @@ const asyncify = require("express-asyncify");
44
const { SolapiMessageService } = require("solapi");
55
const messageService = new SolapiMessageService("ENTER_YOUR_API_KEY", "ENTER_YOUR_API_SECRET");
66

7+
/**
8+
* 웹훅 레퍼런스
9+
* http://developers.solapi.com/references/webhook/
10+
*/
11+
712
// 넘어온 그룹 ID로 메시지 목록을 가져오는 API를 사용하므로 API Key, API Secret Key가 준비되어야 합니다.
813
const app = asyncify(express());
914
app.use(bodyParser.json({ extended: false }));
1015
app.use(bodyParser.urlencoded({ extended: false }));
1116

12-
// 관리콘솔 내 등록한 webhook url로 입력해야 합니다.
13-
app.post("/report", async (req, res) => {
17+
// 메시지 리포트
18+
app.post("/single-report", async (req, res) => {
19+
// body에 [] 형식으로 메시지정보 객체 목록이 들어옵니다.
20+
for (const messageInfo of req.body) {
21+
console.log("메시지 정보:", messageInfo);
22+
}
23+
// 200을 리턴해야 합니다. (200이 리턴되지 않으면 특정 시간 간격을 두고 총 5번이 호출됩니다)
24+
return res.status(200).json({});
25+
});
26+
27+
// 그룹 리포트
28+
app.post("/group-report", async (req, res) => {
1429
// body에 [] 형식으로 그룹정보 객체 목록이 들어옵니다.
1530
for (const groupInfo of req.body) {
1631
// 그룹ID로 메시지 목록을 가져옵니다.
@@ -28,6 +43,16 @@ app.post("/report", async (req, res) => {
2843
return res.status(200).json({});
2944
});
3045

46+
// 팩스 수신
47+
app.post("/fax", async (req, res) => {
48+
// body에 [] 형식으로 팩스수신정보 객체 목록이 들어옵니다.
49+
for (const faxInfo of req.body) {
50+
console.log("팩스 수신 정보:", faxInfo);
51+
}
52+
// 200을 리턴해야 합니다. (200이 리턴되지 않으면 특정 시간 간격을 두고 총 5번이 호출됩니다)
53+
return res.status(200).json({});
54+
});
55+
3156
app.listen(8080, () => {
3257
console.log(`Server is listening...`);
3358
});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "solapi",
3-
"version": "5.2.4",
3+
"version": "5.3.0",
44
"description": "SOLAPI SDK for Node.js(Server Side Only)",
55
"repository": {
66
"type": "git",

src/models/message.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {KakaoOption, kakaoOptionRequest} from './kakao/kakaoOption';
2+
import {RcsOption, RcsOptionRequest} from './rcs/rcsOption';
23

34
/**
45
* @name MessageType 메시지 유형(단문 문자, 장문 문자, 알림톡 등)
@@ -36,6 +37,7 @@ export type MessageParameter = {
3637
subject?: string;
3738
autoTypeDetect?: boolean;
3839
kakaoOptions?: kakaoOptionRequest;
40+
rcsOptions?: RcsOptionRequest;
3941
country?: string;
4042
customFields?: Record<string, string>;
4143
replacements?: Array<object>;
@@ -105,6 +107,11 @@ export class Message {
105107
*/
106108
kakaoOptions?: KakaoOption;
107109

110+
/**
111+
* RCS 메시지를 위한 프로퍼티
112+
*/
113+
rcsOptions?: RcsOption;
114+
108115
/**
109116
* 해외 문자 발송을 위한 국가번호(예) "82", "1" 등)
110117
*/
@@ -140,7 +147,11 @@ export class Message {
140147
if (parameter.kakaoOptions != undefined) {
141148
this.kakaoOptions = new KakaoOption(parameter.kakaoOptions);
142149
}
150+
if (parameter.rcsOptions != undefined) {
151+
this.rcsOptions = new RcsOption(parameter.rcsOptions);
152+
}
143153
this.customFields = parameter.customFields;
144154
this.replacements = parameter.replacements;
145155
}
146156
}
157+

src/models/rcs/rcsButton.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @name "RCS 버튼타입"
3+
*/
4+
export type RcsButtonType =
5+
| 'WL' // (웹링크)
6+
| 'ML' // (지도[좌표])
7+
| 'MQ' // (지도[쿼리])
8+
| 'MR' // (위치공유)
9+
| 'CA' // (캘린더생성)
10+
| 'CL' // (복사)
11+
| 'DL' // (전화걸기)
12+
| 'MS'; // (메시지보내기)
13+
14+
export type RcsWebButton = {
15+
buttonName: string;
16+
buttonType: Extract<RcsButtonType, 'WL'>;
17+
link: string;
18+
};
19+
20+
export type RcsMapButton = {
21+
buttonName: string;
22+
buttonType: Extract<RcsButtonType, 'ML'>;
23+
latitude: string;
24+
longitude: string;
25+
};
26+
27+
export type RcsDefaultButton = {
28+
buttonName: string;
29+
buttonType: Exclude<RcsButtonType, 'WL'>;
30+
link: string;
31+
};
32+
33+
export type RcsButton = RcsWebButton | RcsMapButton | RcsDefaultButton;

src/models/rcs/rcsOption.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {RcsButton} from './rcsButton';
2+
export type AdditionalBody = {
3+
title: string;
4+
description: string;
5+
imaggeId?: string;
6+
buttons?: Array<RcsButton>;
7+
}
8+
9+
export type RcsOptionRequest = {
10+
brandId: string;
11+
templateId?: string;
12+
copyAllowed?: boolean;
13+
mmsType?: 'M3' | 'S3' | 'M4' | 'S4' | 'M5' | 'S5' | 'M6' | 'S6'; // (M: 중간 사이즈. S: 작은 사이즈. 숫자: 사진 개수)
14+
commercialType?: boolean;
15+
variables?: Record<string, string>;
16+
disableSms?: boolean;
17+
additionalBody?: AdditionalBody;
18+
buttons: Array<RcsButton>;
19+
};
20+
21+
export class RcsOption {
22+
brandId: string;
23+
templateId?: string;
24+
copyAllowed?: boolean;
25+
mmsType?: 'M3' | 'S3' | 'M4' | 'S4' | 'M5' | 'S5' | 'M6' | 'S6'; // (M: 중간 사이즈. S: 작은 사이즈. 숫자: 사진 개수)
26+
commercialType?: boolean;
27+
variables?: Record<string, string>;
28+
disableSms?: boolean;
29+
additionalBody?: AdditionalBody;
30+
buttons: Array<RcsButton>;
31+
32+
constructor(parameter: RcsOptionRequest) {
33+
this.brandId = parameter.brandId;
34+
this.templateId = parameter.templateId;
35+
this.copyAllowed = parameter.copyAllowed;
36+
this.mmsType = parameter.mmsType;
37+
this.commercialType = parameter.commercialType;
38+
this.variables = parameter.variables;
39+
this.disableSms = parameter.disableSms;
40+
this.additionalBody = parameter.additionalBody;
41+
this.buttons = parameter.buttons;
42+
}
43+
}

0 commit comments

Comments
 (0)