-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
178 lines (137 loc) · 7.19 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
const axios = require('axios')
const express = require('express')
const dotenv = require('dotenv').config()
const Mono = require('./Mono');
const CurrencyCodes = require('./CurrencyCodes')
const { GoogleSpreadsheet } = require('google-spreadsheet');
const { Telegraf } = require('telegraf')
const { processTransaction, initBot } = require('./processTransaction')
const fs = require('fs')
let { MONO_API_TOKEN, APP_MODE, ACCOUNT_ID, TELEGRAM_BOT_TOKEN, OWNER_TG_ID, GOOGLE_SERVICE_ACCOUNT_KEY, SHEET_ID, TG_WEBHOOK, MONO_WEBOOK, APP_DOMAIN } = dotenv.parsed || {};
const mono = new Mono(MONO_API_TOKEN)
let doc, tgbot;
// Fistly let's parse dotenv to get configuration and check it
async function init(callback) {
if (dotenv.error) return console.log('❗️ Error while reading .env configuration');
if (!APP_MODE) return console.error(`❗️ Missing APP_MODE in .env configuration. It must be 'statement_check' || 'webhook'`)
if (!MONO_API_TOKEN) return console.error(`❗️ Missing MONO_API_TOKEN in .env configuration. You can get it on https://api.monobank.ua/`)
if (!TELEGRAM_BOT_TOKEN) return console.error(`❗️ Missing TELEGRAM_BOT_TOKEN in .env configuration. You can get in conversation with https://t.me/BotFather`)
if (!OWNER_TG_ID) return console.error(`❗️ Missing OWNER_TG_ID in .env configuration. It must contain your telegram id. You can get it from https://t.me/get_any_telegram_id_bot`)
if (!GOOGLE_SERVICE_ACCOUNT_KEY) return console.error(`❗️ Missing GOOGLE_SERVICE_ACCOUNT_KEY in .env configuration. It's a path to your service account JWT auth`)
if (!SHEET_ID) return console.error(`❗️ Missing SHEET_ID in .env configuration. You can find it in a adress bar when open your sheet`)
console.log('✅ .env configuraion is correct')
// if (!await mono.validate()) return console.log('❗️ Mono token is invalid')
console.log('✅ Monobank token is valid')
// If we don't see a account in .env – console.log a list of accounts
if (!ACCOUNT_ID) {
const accounts = await mono.getAccounts()
const parsed_accounts = accounts.map(acc =>
`${acc.type === 'black' ? 'Чорна картка' : ''}${acc.type === 'white' ? 'Бiла картка' : ''} (${CurrencyCodes[acc.currencyCode] || acc.currencyCode})\n` +
`${acc.maskedPan[0]}\n` +
`${acc.balance / 100}${CurrencyCodes[acc.currencyCode] || acc.currencyCode}\n` +
`ACCOUNT_ID=${acc.id}`
).join('\n—————————————————————\n')
return console.log(`✅ Now place one of the your monobank account ids to .env. Here is the list:\n${parsed_accounts}`);
}
// Cheking google auth... i'm bored...
const token = await new Promise(resolve => {
fs.readFile(__dirname + '/' + GOOGLE_SERVICE_ACCOUNT_KEY, 'utf8', async (err, data) => {
if (err) resolve(console.log('❗️ Error while reading service account token.', err.message))
try {
resolve(JSON.parse(data))
} catch(err) {
resolve(console.error('❗️ Error while parsing service account token.', err.message))
}
})
})
if (!token) return token;
console.log('✅ Service account token read successful')
try {
doc = new GoogleSpreadsheet(SHEET_ID);
await doc.useServiceAccountAuth({
client_email: token.client_email,
private_key: token.private_key,
});
} catch (err) {
return console.error('❗️ Service account auth creds are not valid', err.message);
}
console.log('✅ Service account auth successful')
try { await doc.loadInfo() } catch (err) {
return console.error(`❗️ Service account don't have access to spreadsheet`, err.message)
}
console.log(`✅ Service account have access to file`)
// Check tg bot token
tgbot = new Telegraf(TELEGRAM_BOT_TOKEN)
try { await tgbot.telegram.sendMessage(OWNER_TG_ID, 'Bot is running...') } catch(err) {
console.error(`❗️ Telegram bot token is not valid or you didn't /start your bot`, err.message)
}
console.log('✅ Telegram bot token is valid')
console.log('🚀 Pojechali...')
if (callback) callback();
return true;
}
if (!init(main)) process.exit()
// Now run the main app logic
async function main() {
// Statement check app mode runs a /personal/statement/ request and adds a new trasactions to the spreadsheet
if (APP_MODE === 'statement_check') {
initBot(tgbot, false)
let prev_check;
const performCheck = async () => {
console.log('Started statement check')
const statement_check = await mono.getStatement(ACCOUNT_ID, Date.now() - 1000 * 60 * 60 * 24)
if (!prev_check || !Array.isArray(prev_check)) {
console.log('First run, wait for next call in 60s')
prev_check = statement_check
return;
}
const newTransactions = statement_check.filter(transaction => {
return !prev_check.find(prev_trans => prev_trans.id === transaction.id)
})
if (newTransactions.length <= 0) return console.log('No new transaction')
console.log(`Processing ${newTransactions.length} new transaction(s)`)
for (let t of newTransactions) {
await processTransaction(t, tgbot, doc);
}
prev_check = statement_check
console.log('Statement check ended successfully')
}
const loop = async () => {
await performCheck()
setTimeout(loop, 60000)
}
loop()
}
if (APP_MODE === 'webhook') {
const app = express()
const port = process.env.PORT || 8080
const queue = [];
let isCurrentlyWaiting = false;
setInterval(async () => {
if (queue.length > 0 && !isCurrentlyWaiting) {
isCurrentlyWaiting = true
await processTransaction(queue[0], tgbot, doc);
queue.shift();
isCurrentlyWaiting = false;
}
}, 100)
app.use(express.json());
app.use(tgbot.webhookCallback('/' + TG_WEBHOOK))
app.post(`/${MONO_WEBOOK}`, async (req, res) => {
res.send('Thx!')
if (req.body.type === 'StatementItem' && req.body.data.account === ACCOUNT_ID) {
queue.push(req.body.data.statementItem)
}
})
app.get(`/`, (req, res) => res.send(`work1n'!`))
const server = app.listen(port, async () => {
const port = server.address().port;
const webhook_res = await mono.setWebhook(APP_DOMAIN + '/' + MONO_WEBOOK)
if (webhook_res.status !== 'ok') return console.error(`❗️ Monobank webhook setup problem`, webhook_res)
console.log(`✅ Monobank webhook setup success`)
// await tgbot.telegram.setWebhook(APP_DOMAIN + '/' + TG_WEBHOOK)
initBot(tgbot, false)
console.log(`Started server on port ${port}`);
});
}
}