Skip to content

Instantly share code, notes, and snippets.

@4geru

4geru/.env Secret

Created August 28, 2018 22:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 4geru/8e0780a7049240afcdb590e2fbe0b07a to your computer and use it in GitHub Desktop.
Save 4geru/8e0780a7049240afcdb590e2fbe0b07a to your computer and use it in GitHub Desktop.
line pay bot
# LINE bot
CHANNEL_SECRET=""
CHANNEL_ACCESS_TOKEN=""
# LINE pay
LINE_PAY_CHANNEL_ID=""
LINE_PAY_CHANNEL_SECRET=""
LINE_PAY_CONFIRM_URL="https://xxxxxx.ngrok.io/pay/confirm"
module.exports = {
flex: {
"type": "flex",
"altText": "This is a Flex Message",
"contents":
{
"type": "bubble",
"hero": {
"type": "image",
"url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/01_2_restaurant.png",
"size": "full",
"aspectRatio": "20:13",
"aspectMode": "cover",
"action": {
"type": "uri",
"uri": "https://linecorp.com"
}
},
"body": {
"type": "box",
"layout": "vertical",
"spacing": "md",
"action": {
"type": "uri",
"uri": "https://linecorp.com"
},
"contents": [
{
"type": "text",
"text": "Brown's Burger",
"size": "xl",
"weight": "bold"
},
{
"type": "box",
"layout": "vertical",
"spacing": "sm",
"contents": [
{
"type": "box",
"layout": "baseline",
"contents": [
{
"type": "icon",
"url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/restaurant_regular_32.png"
},
{
"type": "text",
"text": "$10.5",
"weight": "bold",
"margin": "sm",
"flex": 0
},
{
"type": "text",
"text": "400kcl",
"size": "sm",
"align": "end",
"color": "#aaaaaa"
}
]
},
{
"type": "box",
"layout": "baseline",
"contents": [
{
"type": "icon",
"url": "https://scdn.line-apps.com/n/channel_devcenter/img/fx/restaurant_large_32.png"
},
{
"type": "text",
"text": "$15.5",
"weight": "bold",
"margin": "sm",
"flex": 0
},
{
"type": "text",
"text": "550kcl",
"size": "sm",
"align": "end",
"color": "#aaaaaa"
}
]
}
]
},
{
"type": "text",
"text": "Sauce, Onions, Pickles, Lettuce & Cheese",
"wrap": true,
"color": "#aaaaaa",
"size": "xxs"
}
]
},
"footer": {
"type": "box",
"layout": "vertical",
"contents": [
{
"type": "spacer",
"size": "xxl"
},
{
"type": "button",
"style": "primary",
"color": "#905c44",
"action": {
"type": "postback",
"label": "Add to Cart",
"data": "action=buy&id=1&productName=バーガー&amount=500"
}
}
]
}
}
}
}
const uuid = require("uuid/v4");
const cache = require("memory-cache");
// for line pay
const line_pay = require("line-pay");
const pay = new line_pay({
channelId: process.env.LINE_PAY_CHANNEL_ID,
channelSecret: process.env.LINE_PAY_CHANNEL_SECRET,
hostname: process.env.LINE_PAY_HOSTNAME,
isSandbox: true
})
// for line bot
const line = require('@line/bot-sdk');
const config = {
channelSecret: process.env.CHANNEL_SECRET,
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN
};
const client = new line.Client(config);
module.exports = {
reserve: (event, item, amount) => {
let reservation = {
productName: item,
amount: amount,
currency: "JPY",
orderId: uuid(),
confirmUrl: process.env.LINE_PAY_CONFIRM_URL,
confirmUrlType: "SERVER"
}
pay.reserve(reservation).then((response) => {
reservation.transactionId = response.info.transactionId;
reservation.userId = event.source.userId;
// Save transaction information to cashe
cache.put(response.info.transactionId, reservation);
const message = {
type: "template",
altText: `${item}を購入するには下記のボタンで決済に進んでください`,
template: {
type: "buttons",
text: `${item}を購入するには下記のボタンで決済に進んでください`,
actions: [
{type: "uri", label: "LINE Payで決済", uri: response.info.paymentUrl.web},
]
}
}
return client.replyMessage(event.replyToken, message);
});
},
confirm: (transactionId) => {
console.log('called confirm')
// Restore data from chache
const reservation = cache.get(transactionId);
if (!reservation){
console.log("Reservation not found.");
return res.status(400).send("Reservation not found.")
}
console.log(`Restore data from chache.`);
console.log(reservation);
const confirmation = {
transactionId: transactionId,
amount: reservation.amount,
currency: reservation.currency
}
// Finished transaction
return pay.confirm(confirmation).then((response) => {
const messages = [{
type: "sticker",
packageId: 2,
stickerId: 516
},{
type: "text",
text: `ありがとうございます、${reservation.productName}の決済が完了しました。`
}]
return client.pushMessage(reservation.userId, messages);
});
}
}
'use strict';
const queryString = require('query-string');
require('dotenv').config();
// for express
const express = require('express');
const PORT = process.env.PORT || 3000;
const app = express();
// for line bot
const line = require('@line/bot-sdk');
const config = {
channelSecret: process.env.CHANNEL_SECRET,
channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN
};
const client = new line.Client(config);
// require local files
const flex = require('./messages/flex');
const pay = require('./pay');
app.post('/webhook', line.middleware(config), (req, res) => {
console.log(req.body.events);
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});
function handleEvent(event) {
console.log(event)
if (event.type === 'postback') {
const data = queryString.parse(event.postback.data);
console.log({data: data})
return pay.reserve(event, data.productName, data.amount);
}
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
if (event.message.text === 'バーガー') {
return client.replyMessage(event.replyToken, flex.flex);
} else {
return client.replyMessage(event.replyToken, {
type: 'text',
text: event.message.text
});
}
}
app.get("/pay/confirm", (req, res, next) => {
console.log('called confirm path')
if (!req.query.transactionId){
console.log("Transaction Id not found.");
return res.status(400).send("Transaction Id not found.");
}
pay.confirm(req.query.transactionId);
})
app.listen(PORT);
console.log(`Server running at ${PORT}`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment