-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot.js
214 lines (168 loc) · 5.71 KB
/
bot.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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
const { Telegraf } = require('telegraf');
const path = require('path');
const fetch = require('node-fetch');
const fs = require('fs');
const request = require('request');
require('dotenv').config();
const bcrypt = require('bcrypt');
const { usersDatabase } = require('./app.js');
const bot = new Telegraf(process.env.BOT_TOKEN);
bot.command('start', (ctx) => {
const userId = generateUserId(ctx.from.id.toString());
const verificationCode = userId.substr(userId.length - 6).toLowerCase(); // consider last 6 characters as verification code
usersDatabase.insert({
email: null,
username: null,
password: null,
telegramId: ctx.from.username.toLowerCase(),
filesInfo: [], // stores information about files. Like url, fileId, fileTags
deletedFilesInfo: [],
untaggedFiles: [],
tagTable: {},
isVerified: false,
verificationCode: verificationCode,
_id: userId,
});
const replyTxt = `Glad we've you here. Just to get you started, here's your 6 character verification code to enter in the site to sync your Telegram account with the account you registered: ${verificationCode}`;
ctx.reply(replyTxt);
});
bot.on('message', async (ctx) => {
// message is a text
if (Boolean(ctx.update.message.text)) {
// tagging the untagged files
console.log('Tags received');
const userId = generateUserId(ctx.update.message.from.id.toString());
const msg = ctx.update.message.text;
if (msg.includes('-')) {
ctx.reply('Remove dashes in your tags pretty please.');
return;
}
tagUntaggedFiles(msg, userId);
} else if (Boolean(ctx.update.message.photo)) {
// message is a photo
console.log('Adding photo');
handleNewFile(ctx);
} else if (Boolean(ctx.update.message.document)) {
console.log('File received');
handleNewFile(ctx);
}
});
bot.launch();
// msg is the tags that user sent
function tagUntaggedFiles(msg, userId, editMode = false) {
// for some reason replaceAll threw error
while (msg.includes('#')) msg = msg.replace('#', '');
while (msg.includes('\n')) msg = msg.replace('\n', ' ');
const newTags = msg.split(/[ ,]+/).filter(Boolean); // removes the wite space and extracts the tags
console.log(newTags);
// return if tags is empty
if (newTags.length == 0) {
console.log('No tag is feeded');
return;
}
// tagging user's untagged files
usersDatabase.findOne({ _id: userId }, async (err, user) => {
if (err) return console.log('Error in tagFile()\n', err);
let tagTable = user.tagTable;
let existingTags = Object.keys(tagTable);
let untaggedFiles;
if (editMode) {
// load the final file to edit(we don't want to edit all the files that are already in untaggedFiles)
untaggedFiles = [user.untaggedFiles[user.untaggedFiles.length - 1]];
} else {
untaggedFiles = user.untaggedFiles;
}
if (untaggedFiles.length == 0) {
console.log("There's no file to tag");
return;
}
for (let tag of newTags) {
// create new tag is it doesn't exist
if (!existingTags.includes(tag)) {
tagTable[tag] = [];
}
for (let f of untaggedFiles) {
tagTable[tag].push(f);
}
}
// make a copy
untaggedFiles = [...user.untaggedFiles];
let updatedUntagged = [...user.untaggedFiles];
if (editMode) updatedUntagged.splice(-1, 1);
// delete the last element if it's in the edit mode
else updatedUntagged = []; // clear the untagged files if it's not on edit mode
usersDatabase.update(
{ _id: user._id },
{ $set: { untaggedFiles: updatedUntagged, tagTable: tagTable } },
{},
(err) => {
if (err) {
console.log('Error in database update TagFile()', err);
}
}
);
// if it's edit mode select last element
if (editMode) untaggedFiles = [untaggedFiles[untaggedFiles.length - 1]];
for (let fId of untaggedFiles) {
const newImg = {
url: getServerDownloadURL(fId),
fileId: fId,
fileTags: newTags,
};
usersDatabase.update({ _id: user._id }, { $push: { filesInfo: newImg } });
}
});
}
async function handleNewFile(ctx) {
let fileId;
if (ctx.update.message.photo) {
fileId = ctx.update.message.photo[0].file_id;
} else if (ctx.update.message.document) {
fileId = ctx.update.message.document.file_id;
}
// download file to database
downloadFile(fileId);
// save newly sent file to untagged files
const senderId = ctx.update.message.from.id.toString();
usersDatabase.update(
{ _id: generateUserId(senderId) },
{ $push: { untaggedFiles: fileId } },
{},
(err) => {
if (err)
return console.log(
'Error in BOT-on-photo-event update usersDatabase\n',
err
);
}
);
}
function generateUserId(teleId) {
return bcrypt.hashSync(teleId, process.env.SALT);
}
async function downloadFile(fileId) {
const res = await fetch(
`https://api.telegram.org/bot${process.env.BOT_TOKEN}/getFile?file_id=${fileId}`
);
const res2 = await res.json();
const filePath = res2.result.file_path;
const downloadURL = `https://api.telegram.org/file/bot${process.env.BOT_TOKEN}/${filePath}`;
const savingDir = path.resolve(__dirname, 'database', 'files');
if (!fs.existsSync(savingDir)) {
fs.mkdirSync(savingDir);
}
const savePath = path.join(savingDir, `${fileId}.jpg`);
download(downloadURL, savePath, () => {
console.log('Downloaded');
});
}
function getServerDownloadURL(fileId) {
return `/download/${fileId}`;
}
// handling downloading file
const download = (url, path, callback) => {
request.head(url, (err, res, body) => {
request(url).pipe(fs.createWriteStream(path)).on('close', callback);
});
};
module.exports = { bot, tagUntaggedFiles };