Skip to content

Commit 62dd510

Browse files
committed
Image support added
1 parent 44f9463 commit 62dd510

File tree

11 files changed

+324
-85
lines changed

11 files changed

+324
-85
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"license": "ISC",
1818
"dependencies": {
1919
"@notionhq/client": "^1.0.4",
20+
"axios": "^0.27.2",
2021
"dotenv": "^16.0.0",
2122
"grammy": "^1.7.2",
2223
"mongoose": "^6.2.10"

src/app/app.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const developmentMsg = require('./middlewares/developmentMsg');
66
const authCodeHandler = require('./middlewares/authCodeHandler');
77
const announcementHandler = require('./middlewares/announcementHandler');
88
const chatAction = require('./middlewares/chatAction');
9+
const cleanSessions = require('./middlewares/cleanSessions');
910

1011
//Commands
1112
const start = require('./commands/start');
@@ -28,7 +29,12 @@ const bot = new Bot(process.env.BOT_TOKEN)
2829

2930
// Setting default session for user
3031
function initialSesionValues() {
31-
return {waitingForAuthCode: false, waitingForAnnouncementMessage: false, textsForAdd: []};
32+
return {
33+
waitingForAuthCode: false,
34+
waitingForAnnouncementMessage: false,
35+
textsForAdd: [],
36+
imagesForAdd: []
37+
};
3238
}
3339

3440
bot.use(session({ initial: initialSesionValues }));
@@ -45,6 +51,9 @@ bot.use(announcementHandler)
4551
//Set a middleware for send a 'typing' state every time the bot is called
4652
bot.use(chatAction)
4753

54+
//Set a middleware for check if for each session array, one is full of null objects. In that case, clean it
55+
bot.use(cleanSessions)
56+
4857

4958
//* ---------------- COMMANDS ----------------
5059

src/app/events/onCallbackQuery.js

Lines changed: 68 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,97 @@
11
const AppController = require("../../controller/AppController")
2+
const DatabaseQuerys = require("../../controller/DatabaseQuerys")
23

34
async function onCallbackQuery(ctx) {
5+
46
//In case that the cancel button is pressed
5-
if (ctx.update.callback_query.data === "cancel_operation") {
7+
if (ctx.update.callback_query.data.includes("co_")) {
8+
9+
//Get dataType
10+
const dataType = extractSubstring(ctx.update.callback_query.data, "dt_", "i_")
11+
12+
switch (dataType) {
13+
case "text":
14+
//Get text position
15+
const textIndex = parseInt(extractSubstring(ctx.update.callback_query.data, "i_", ""))
16+
//Make it null
17+
ctx.session.textsForAdd[textIndex] = null
18+
break;
19+
20+
case "image":
21+
//Get image position
22+
const position = parseInt(extractSubstring(ctx.update.callback_query.data, "i_", ""))
23+
//Make it null
24+
ctx.session.imagesForAdd[position] = null
25+
26+
default:
27+
break;
28+
}
629
deleteMessage(ctx, ctx.update.callback_query.message.message_id)
730
ctx.reply(`Operation canceled 👍`, {parse_mode: "HTML"})
831
return
932
}
1033

1134
//Get database id
12-
const databaseID = extractSubstring(ctx.update.callback_query.data, "database_id", "text_index")
13-
14-
//Get what text want the user add
15-
const textIndex = parseInt(extractSubstring(ctx.update.callback_query.data, "text_index", ""))
16-
const text = ctx.session.textsForAdd[textIndex]
17-
18-
// Check if databaseID and text are defined
19-
if (!databaseID || !text) {
20-
reportError(ctx)
21-
return
35+
const databaseID = extractSubstring(ctx.update.callback_query.data, "db_", "dt_")
36+
37+
//Get dataType
38+
const dataType = extractSubstring(ctx.update.callback_query.data, "dt_", "i_")
39+
40+
let response
41+
42+
switch (dataType) {
43+
case "text":
44+
//Get what text want the user add
45+
const textIndex = parseInt(extractSubstring(ctx.update.callback_query.data, "i_", ""))
46+
const text = ctx.session.textsForAdd[textIndex]
47+
48+
response = await AppController().addMessageToNotionDatabase(ctx.from.id, databaseID, text)
49+
50+
ctx.reply(`<strong>${text.length > 20 ? text + "\n\n</strong>" : text + "</strong> "}added to <strong>${response.databaseTitle}</strong> database 👍`, {parse_mode: "HTML"})
51+
52+
// Change this text on array for null
53+
ctx.session.textsForAdd[textIndex] = null
54+
break;
55+
56+
case "image":
57+
//Get what image want the user add
58+
const index = parseInt(extractSubstring(ctx.update.callback_query.data, "i_", ""))
59+
const image = ctx.session.imagesForAdd[index]
60+
const imageTitle = image.title ? image.title : image.file_path
61+
62+
response = await AppController().addImageToDatabase(ctx.from.id, databaseID, `https://api.telegram.org/file/bot${process.env.BOT_TOKEN}/${image.file_path}`, imageTitle)
63+
64+
ctx.reply(`<strong>${imageTitle.length > 20 ? imageTitle + "\n\n</strong>" : imageTitle + "</strong> "}added to <strong>${response.databaseTitle}</strong> database 👍`, {parse_mode: "HTML"})
65+
66+
// Change this image on array for null
67+
ctx.session.imagesForAdd[index] = null
68+
break;
69+
70+
default:
71+
reportError(ctx)
72+
break;
2273
}
2374

24-
const response = await AppController().addMessageToNotionDatabase(ctx.from.id, databaseID, text)
25-
75+
//Report in error case
2676
if (response.status === "error") {
2777
deleteMessage(ctx, ctx.update.callback_query.message.message_id)
2878
reportError(ctx)
2979
return
3080
}
3181

32-
ctx.reply(`<strong>${text.length > 20 ? text + "\n\n</strong>" : text + "</strong> "}added to <strong>${response.databaseTitle}</strong> database 👍`, {parse_mode: "HTML"})
82+
//Delete DB selector
3383
deleteMessage(ctx, ctx.update.callback_query.message.message_id)
34-
35-
// Change this text on array for null
36-
ctx.session.textsForAdd[textIndex] = null
37-
38-
// If all texts on the array are null, clean the array
39-
let allTextsAreNull = true
40-
41-
ctx.session.textsForAdd.forEach(text => {
42-
if (text !== null) {
43-
allTextsAreNull = false
44-
}
45-
})
46-
47-
if (allTextsAreNull) {
48-
ctx.session.textsForAdd = []
49-
}
5084
}
5185

5286
//Extract substring function
53-
function extractSubstring(str, a, b) {
87+
function extractSubstring(str, start, end) {
5488

55-
const position = str.indexOf(a) + a.length;
89+
const position = str.indexOf(start) + start.length;
5690

57-
if (!b) {
91+
if (!end) {
5892
return str.substring(position, str.length)
5993
}
60-
return str.substring(position, str.indexOf(b, position));
94+
return str.substring(position, str.indexOf(end, position));
6195
}
6296

6397
// Delete message function

src/app/events/onPhoto.js

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,46 @@
1-
async function onPhoto() {
2-
ctx.reply("<strong>Pictures are not allowed...</strong>", {parse_mode: "HTML"})
3-
4-
setTimeout(() => {
5-
ctx.reply("<strong>...yet</strong>", {parse_mode: "HTML"})
6-
}, 3500)
1+
const AppController = require('../../controller/AppController.js')
2+
3+
async function onPhoto(ctx) {
4+
const data = await ctx.getFile()
5+
6+
const databases = await AppController().getNotionDatabases(ctx.from.id)
7+
8+
if (databases.status === "error") {
9+
switch (databases.message) {
10+
case "no auth code":
11+
ctx.reply('No auth code provided\n*Use the /auth command for provide it*', {parse_mode: "MarkdownV2"})
12+
break;
13+
14+
default:
15+
ctx.reply('Unknow error\n*Try again later*', {parse_mode: "MarkdownV2"})
16+
break;
17+
}
18+
19+
return
20+
}
21+
22+
//If the message have a caption, set it as title propierty
23+
if (ctx.update.message.caption) {
24+
data.title = ctx.update.message.caption
25+
}
26+
27+
//Add image to array of texts
28+
ctx.session.imagesForAdd.push(data)
29+
30+
//If pass some time delete the text on the array
31+
function cleanArray() {
32+
if (ctx.session.imagesForAdd.includes(data)) {
33+
const index = ctx.session.imagesForAdd.indexOf(data)
34+
ctx.session.imagesForAdd.splice(index, 1)
35+
}
36+
}
37+
38+
//Delete the item in the imagesForAdd in...
39+
setTimeout(cleanArray, 5 * 60 * 1000) //5 Minutes
40+
41+
const keyboard = await AppController().getKeyboardOfDatabases(databases.results, "❌ Don't upload image", "image", ctx.session.imagesForAdd)
42+
43+
ctx.reply(`Select the <strong>database</strong> to save this image\n\nIf you atached an caption to this image, <strong>it's gonna be the title of the new page</strong> in the Database\n\n<strong>Remember that this image keeps public</strong>\nDon't upload sensitive data!`, {...keyboard, parse_mode: "HTML"})
744
}
845

946
module.exports = onPhoto

src/app/events/onText.js

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
async function onText(ctx) {
1+
const AppController = require('../../controller/AppController')
22

3-
const AppController = require('../../controller/AppController')
3+
async function onText(ctx) {
44

5-
const response = await AppController().getNotionDatabases(ctx.from.id)
5+
//Get databases
6+
const databases = await AppController().getNotionDatabases(ctx.from.id)
67

7-
if (response.status === "error") {
8+
if (databases.status === "error") {
89

9-
switch (response.message) {
10+
switch (databases.message) {
1011
case "no auth code":
1112
ctx.reply('No auth code provided\n*Use the /auth command for provide it*', {parse_mode: "MarkdownV2"})
1213
break;
13-
14+
1415
default:
1516
ctx.reply('Unknow error\n*Try again later*', {parse_mode: "MarkdownV2"})
1617
break;
@@ -31,39 +32,15 @@ async function onText(ctx) {
3132
}
3233
}
3334

34-
setTimeout(cleanArray, 5 * 60 * 1000)
35+
//Delete the item in the textsForAdd in...
36+
setTimeout(cleanArray, 5 * 60 * 1000) //5 Minutes
3537

3638
const botReply = text.length > 20 ? "\n\n" + text : text
3739

38-
ctx.reply(`Select the <strong>database</strong> to save <strong>${botReply}</strong>`, {
39-
reply_markup: {
40-
inline_keyboard: [
41-
...response.results.map((obj) => {
42-
const title = obj.title.length <= 0 ? "Untitled" : obj.title[0].text.content
43-
44-
if (obj.properties.telegramIgnore) {
45-
return []
46-
}
40+
//Generate Keyboard from the databases
41+
const keyboard = await AppController().getKeyboardOfDatabases(databases.results, null, "text", ctx.session.textsForAdd)
4742

48-
if (obj.icon) {
49-
return [{
50-
text: `${obj.icon.emoji ? obj.icon.emoji + " " : ""}${title}`,
51-
callback_data: "database_id" + obj.id + "text_index" + JSON.stringify(ctx.session.textsForAdd.length - 1)
52-
}]
53-
} else {
54-
return [{
55-
text: title,
56-
callback_data: "database_id" + obj.id + "text_index" + JSON.stringify(ctx.session.textsForAdd.length - 1)
57-
}]
58-
}
59-
}),
60-
[
61-
{text: "🚫", callback_data: "cancel_operation"}
62-
]
63-
]
64-
},
65-
parse_mode: "HTML"
66-
})
43+
ctx.reply(`Select the <strong>database</strong> to save <strong>${botReply}</strong>`, {...keyboard, parse_mode: "HTML"})
6744
}
6845

6946
module.exports = onText
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function cleanSessions(ctx, next) {
2+
3+
const sessions = [ctx.session.textsForAdd, ctx.session.imagesForAdd]
4+
5+
sessions.forEach(session => {
6+
// If all elements on the array are null, clean the array
7+
let allTextsAreNull = true
8+
9+
session.forEach(element => {
10+
if (element !== null) {
11+
allTextsAreNull = false
12+
}
13+
})
14+
15+
if (allTextsAreNull) {
16+
session = []
17+
}
18+
});
19+
20+
next()
21+
}
22+
23+
module.exports = cleanSessions

src/app/middlewares/developmentMsg.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ async function developmentMsg (ctx, next) {
55
return
66
}
77

8-
if (ctx.from.id !== parseInt(process.env.MY_USER_ID)) {
8+
console.log(ctx.from.id)
9+
10+
if (ctx.from.id !== parseInt(process.env.MY_USER_ID) && ctx.from.id !== parseInt(process.env.TESTING_USER_ID)) {
911
ctx.reply('⚠️ Sorry, this bot is on development for now... \n\nStay alert for new updates! \n\nRepository: https://github.com/FranP-code/Telegram-to-Notion-Bot')
1012
return
1113
}

0 commit comments

Comments
 (0)