From bbe4d4f47ff7a5a627028929ac0d2ffb6df39cc0 Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Fri, 30 Aug 2024 12:20:26 +0330 Subject: [PATCH 01/10] Add files to repo --- .gitignore | 179 ++++++++++++++++++++++++++++++++++++++++++ README.md | 15 ++++ bun.lockb | Bin 0 -> 57758 bytes package.json | 23 ++++++ src/app.ts | 79 +++++++++++++++++++ src/database.ts | 12 +++ src/models/archive.ts | 21 +++++ src/utils/utils.ts | 29 +++++++ tsconfig.json | 33 ++++++++ 9 files changed, 391 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100755 bun.lockb create mode 100644 package.json create mode 100644 src/app.ts create mode 100644 src/database.ts create mode 100644 src/models/archive.ts create mode 100644 src/utils/utils.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f21777 --- /dev/null +++ b/.gitignore @@ -0,0 +1,179 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store + +# Custom ignores +config.json +database.sqlite \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c6fc578 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# any-bot + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.1.26. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..92d75d8cfbd5bc9a8da4938dd047a567dc260941 GIT binary patch literal 57758 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 AF8}}l literal 0 HcmV?d00001 diff --git a/package.json b/package.json new file mode 100644 index 0000000..e3a3b21 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "magical-mailbox", + "version": "0.0.1", + "module": "app.ts", + "type": "module", + "license": "MIT", + "description": "", + "peerDependencies": { + "typescript": "^5.5.4" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "dependencies": { + "grammy": "^1.29.0", + "sequelize": "^6.37.3", + "sqlite3": "^5.1.7" + }, + "scripts": { + "start": "bun run src/app.ts", + "dev": "bun run --watch src/app.ts" + } +} \ No newline at end of file diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..3846c5a --- /dev/null +++ b/src/app.ts @@ -0,0 +1,79 @@ +import { Bot } from "grammy"; + +import { connectToDatabase, readConfigFile } from "utils/utils"; + +import Archive from "models/archive"; + +await connectToDatabase(); + +const conf = await readConfigFile(); +const bot = new Bot(conf.token); + +bot.command("start", (ctx) => { + ctx.reply("Welcome to my magical mailbox 🪄"); + ctx.reply(`My mailbox doese support: + 💬 Text + 🔉 Voice/Audio + 🎞 Video/Video note + 🎆 Sticker/Gif + 📁 Document + 🥰 Reactions`); +}); + +bot.on("message", async (ctx, next) => { + if (!ctx.msg.reply_to_message) { + return next(); + } + try { + const record: any = await Archive.findOne({ + where: { msgId: ctx.msg.reply_to_message.message_id }, + }); + const msg = await ctx.api.copyMessage( + record.senderId, + ctx.from.id, + ctx.msgId, + { + reply_parameters: { message_id: record.senderMsgId }, + } + ); + await Archive.create({ + msgId: msg.message_id, + senderId: ctx.from.id, + senderMsgId: ctx.msgId, + }); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +bot.on("message", async (ctx) => { + try { + const msg = await ctx.api.copyMessage(conf.admin, ctx.from.id, ctx.msgId); + await Archive.create({ + msgId: msg.message_id, + senderId: ctx.from.id, + senderMsgId: ctx.msgId, + }); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +bot.on("message_reaction", async (ctx) => { + try { + const record: any = await Archive.findOne({ + where: { msgId: ctx.msgId }, + }); + await ctx.api.setMessageReaction( + record.senderId, + record.senderMsgId, + ctx.messageReaction.new_reaction + ); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +bot.start({ + allowed_updates: ["message", "message_reaction", "message_reaction_count"], +}); diff --git a/src/database.ts b/src/database.ts new file mode 100644 index 0000000..3d71e01 --- /dev/null +++ b/src/database.ts @@ -0,0 +1,12 @@ +import { Sequelize } from "sequelize"; + +import { join } from "path"; + +import { rootPath } from "utils/utils"; + +const database = new Sequelize({ + dialect: "sqlite", + storage: join(rootPath(), "database.sqlite"), +}); + +export default database; diff --git a/src/models/archive.ts b/src/models/archive.ts new file mode 100644 index 0000000..7da4fc4 --- /dev/null +++ b/src/models/archive.ts @@ -0,0 +1,21 @@ +import { DataTypes } from "sequelize"; + +import database from "database"; + +const Archive = database.define("Archive", { + msgId: { + type: DataTypes.STRING, + primaryKey: true, + allowNull: false, + }, + senderId: { + type: DataTypes.STRING, + allowNull: false, + }, + senderMsgId: { + type: DataTypes.STRING, + allowNull: false, + }, +}); + +export default Archive; diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..9255687 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,29 @@ +import fs from "fs/promises"; +import { join } from "path"; + +import database from "database"; + +export function rootPath() { + return process.cwd(); +} + +export async function connectToDatabase() { + try { + await database.authenticate(); + console.log("Connection has been established successfully."); + await database.sync(); + console.log("Sync has been done successfully."); + } catch (error) { + console.error("Unable to use the database:", error); + } +} + +export async function readConfigFile() { + const path = join(rootPath(), "config.json"); + try { + const buffer = await fs.readFile(path); + return JSON.parse(buffer.toString()); + } catch (err) { + console.log(err); + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..55ff05b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false, + "baseUrl": "src", + "paths": { + "@src/*": ["src/*"], + "@utils/*": ["src/utils/*"], + "@models/*": ["src/models/*"] + }, + } +} From aa6f2d5ca76b42e20ca700816c6b06929bf15c20 Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Fri, 30 Aug 2024 19:48:18 +0330 Subject: [PATCH 02/10] Making the project more readable The feature of editing text messages and captions is also added in this commit --- .gitignore | 2 +- bun.lockb | Bin 57758 -> 58099 bytes package.json | 1 + src/app.ts | 84 +++++++-------------------------------- src/composer/commands.ts | 18 +++++++++ src/composer/edits.ts | 35 ++++++++++++++++ src/composer/messages.ts | 62 +++++++++++++++++++++++++++++ src/utils/utils.ts | 9 ++--- 8 files changed, 136 insertions(+), 75 deletions(-) create mode 100644 src/composer/commands.ts create mode 100644 src/composer/edits.ts create mode 100644 src/composer/messages.ts diff --git a/.gitignore b/.gitignore index 2f21777..a8d4585 100644 --- a/.gitignore +++ b/.gitignore @@ -175,5 +175,5 @@ dist .DS_Store # Custom ignores -config.json +config.env database.sqlite \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 92d75d8cfbd5bc9a8da4938dd047a567dc260941..6ff76cc687a0c178a3f5884f6d767773be124f20 100755 GIT binary patch delta 3252 zcmeH}eN0tl9LLY$UIed*lz<2!&Ct38_g=WX2n1dPdzs>j)krbAgn%z_U5dPn@>1!9 zmd<+Cl#3V=Bp@bu2eef)*VIa7kWwq>W^6fIjcWBr&5ing&wcK8TX%Eezx}q)`99C@ z_q?6woZorQ(NA^1ozopO8K?VVtJbxgtsjlfPKhd-&iww@J-I*2x#syD#~2wO?O`48GUfm(8jl%O_S574TH<{ zVQ3>P_aq9tAy};uedd+w3GoB2KMSK}Wq>(BY_()L=b#k{1oHq#jsWbv4A7`L@DNY| zCe<_nN}~pVL{?x_)=jLye3kvpfND_`Cqye~9a2zczzR5FI-pVM&j5OmE$fd+&4JRW zY?lkT02^REPwFZt{RMzlAm{gScsi{1#1-njpct^@dcXlU0PdO{(CpgPql}jUwl9}{ zf691;=l)SZg&iwp2VbSXO2#+KxUVw41#rM^GVV{=u3ENp$aYR|fyxHk0q<-Vp!rii zf<`UsQBK?hbYQpiQ#qdZ2K{NUqJ%2@WCyBF6j~ot6;WX|JK6bwj8Q{?3((&VxQKT^ zAm|1(D&swXi|GYiTtA@sD*XeR_n*psrxYbx3!$J5I4B!Z^`bB}Ba@C{>Gh{v#)ynl znNR0|DlVsHh@Vo!ggz}Sj}1QO1?EpV$`@MHqrB-cz{QVKMNV3rwzXGKqxmX(Uj=Oa z6=3~q;59yH!Y#au+;?gdFzIPjPH18U=Br$QPx5PV3$AQG``nkW)_+faZT`E@eebJn z$9TNMGQd0Xm-KLJe#V*eG%EX5vI6r}`tOwc&eFlmGwR_m}g0 zDD?A*+%fl)*xEPey><5fSMIwrvj(hdE34Lg`(f9gH|olRt4mgV))6=F?Q84rv){@u z>5LoO(!FD_C-35P?vEJ-Q@@WNkB*Po``)gr8=ks7(mQ#jy6xKjA`Go6GYe**hr~BE z#iGSAU*tH}sBNOvQLMV$-#PL_ge^4O9p7{yR@inX8~$kHx)kM>OMGtGpm?!uq4swZDI*;+5(JHvzN6BI zlSo-2eLPe+!d!4apmhTJ3}7js9Ru|7%c&g)&@SnV;xf3{?hes^WVwiPg~#$M%O}NW zdJ$X#mjO?QQSpS!ntTo=evi3Au81q(jC_uh;7ecxV}NhSusG>5W7n^{7CE^mAz(fT z1q%Sr9R9s51l*qsfTzX;=m#gjAQ%E}FaX{M+!gL^3D^jp1Et`3uphhu_+L;5>OljS z9f3lmXl%DS<5A)_jfW>UlN?36{LdYpa;AJUgi{KD7*k(2Q8o#Yy(>XKd#vz0Xz(PK_93FHGm&m{#GV}B)|um z3pRsAzya2R43G|ZY?(j~81KM^KPHLC@YI(Eat{x=CyqR(i{>lMS9rI?&P{=(kBXGe z1o3QVs@3~%@BN7n2=Fw)ns$`c)L?g3PaHho)M^|EP)n0dDVZjVyQecKLhTYKhZn0i z#f9NQL-VMo(w8wDT~ZrDXMT}QN~YZXBaOyL&%EX&v!{@h WoNh`rrHQj=;za57Aa}xzTJ>*LRF0Ye delta 3081 zcmeH}ZA?{l9LLWA1SBC;40JIvb#f8)!UY1-0bz5DvDR#94<<5*QZH`K2*S8zuA-=E z{}+0B&`Y^VJ|K7loLlQfQ_FOsWiQ%n6LCe)>VHM$X8odz$wCm(?Efn zQHZO;@^uBOgWqO?aDfkz5VF0s261f+Saiol2mYJel}APHx0izuQg6y4rc) zGJAdVOph4m&B!`X{%Izi7GHQ~bFP#T9cfs|Gxb&~w+$?&`{8^Un(F9xp zy~tJ9ui;Xx+orBOC!kU{K>hy!QAPK?{2uQ8$WqcFpaH~eerFu_e(%%2I<5lEM77iH z%&v0l+Aa&_FK^!>emfA7zDCj7U(pL*Bc4+qOn`piH}t$onk zZrNyVwWON5owar_9NbwwC;W5AN7*UAAJQ_ktXn}-Igw$m1oO+L|B6WAgP_GKm!fI) zv&)HCmReAmc(b^7ejtIT`EHI5Z{_I3iC%quZcG=^0+9Ma<&xlGkOn|8-6Po`=@L+E zHspYG1QgSWwmAByB;*Dkz)L|I1QpEEs8Fci3=ceNGWxQzuao=+F2T2O8OC57&YGG& zUxD60Bi0BtB8}iX_#Siu=Yme?ui zRG$Q0TgTxvjKCSt)pZIqBf1u!hZo>Q*bFa04}1W+!C!+`cpaGaL}!{aO?$sDptDCe zohC8_pTHLA1kO#X3*Lgg@HXrN{RvnPb?_8C4IAJYsDdY;0yNKMPzXL)21lU-_CUS5 z*vdmUybJHaHh2}9pd37q2ghItw!;p18T9vW1>}Ri;aX^hhrkcDPy)qJ04re)O!o7G zazpyy`jS>Kd}CmJ{35MptzNyp*c9RiWsIAW!93GA=v~;nYpdViZdp%W+kc^>+jBBb zD_;s<986kZ`_0wyh4!eqJzkemujPV5<7}l$%9*YS@1i@r5?{Y-Uup4WyDe>c(k+!Z T6}~jl?lGM|C4~c1yY0UL9o1IK diff --git a/package.json b/package.json index e3a3b21..b61d8f5 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "@types/bun": "latest" }, "dependencies": { + "dotenv": "^16.4.5", "grammy": "^1.29.0", "sequelize": "^6.37.3", "sqlite3": "^5.1.7" diff --git a/src/app.ts b/src/app.ts index 3846c5a..e5bfdef 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,79 +1,25 @@ import { Bot } from "grammy"; -import { connectToDatabase, readConfigFile } from "utils/utils"; +import { connectToDatabase, setupEnv } from "utils/utils"; -import Archive from "models/archive"; +import messages from "composer/messages"; +import commands from "composer/commands"; +import edits from "composer/edits"; await connectToDatabase(); +await setupEnv(); -const conf = await readConfigFile(); -const bot = new Bot(conf.token); +const bot = new Bot(process.env.token!); -bot.command("start", (ctx) => { - ctx.reply("Welcome to my magical mailbox 🪄"); - ctx.reply(`My mailbox doese support: - 💬 Text - 🔉 Voice/Audio - 🎞 Video/Video note - 🎆 Sticker/Gif - 📁 Document - 🥰 Reactions`); -}); - -bot.on("message", async (ctx, next) => { - if (!ctx.msg.reply_to_message) { - return next(); - } - try { - const record: any = await Archive.findOne({ - where: { msgId: ctx.msg.reply_to_message.message_id }, - }); - const msg = await ctx.api.copyMessage( - record.senderId, - ctx.from.id, - ctx.msgId, - { - reply_parameters: { message_id: record.senderMsgId }, - } - ); - await Archive.create({ - msgId: msg.message_id, - senderId: ctx.from.id, - senderMsgId: ctx.msgId, - }); - } catch (err) { - return ctx.reply("Oops, something wrong 😢"); - } -}); - -bot.on("message", async (ctx) => { - try { - const msg = await ctx.api.copyMessage(conf.admin, ctx.from.id, ctx.msgId); - await Archive.create({ - msgId: msg.message_id, - senderId: ctx.from.id, - senderMsgId: ctx.msgId, - }); - } catch (err) { - return ctx.reply("Oops, something wrong 😢"); - } -}); - -bot.on("message_reaction", async (ctx) => { - try { - const record: any = await Archive.findOne({ - where: { msgId: ctx.msgId }, - }); - await ctx.api.setMessageReaction( - record.senderId, - record.senderMsgId, - ctx.messageReaction.new_reaction - ); - } catch (err) { - return ctx.reply("Oops, something wrong 😢"); - } -}); +bot.use(commands); +bot.use(messages); +bot.use(edits); bot.start({ - allowed_updates: ["message", "message_reaction", "message_reaction_count"], + allowed_updates: [ + "message", + "edited_message", + "message_reaction", + "message_reaction_count", + ], }); diff --git a/src/composer/commands.ts b/src/composer/commands.ts new file mode 100644 index 0000000..9a22f55 --- /dev/null +++ b/src/composer/commands.ts @@ -0,0 +1,18 @@ +import { Composer } from "grammy"; + +import Archive from "models/archive"; + +const commands = new Composer(); + +commands.command("start", (ctx) => { + ctx.reply("Welcome to my magical mailbox 🪄"); + ctx.reply(`My mailbox doese support: + 💬 Text + 🔉 Voice/Audio + 🎞 Video/Video note + 🎆 Sticker/Gif + 📁 Document + 🥰 Reactions`); +}); + +export default commands; diff --git a/src/composer/edits.ts b/src/composer/edits.ts new file mode 100644 index 0000000..93b6f56 --- /dev/null +++ b/src/composer/edits.ts @@ -0,0 +1,35 @@ +import { Composer } from "grammy"; + +import Archive from "models/archive"; + +const edits = new Composer(); + +edits.on("edit:text", async (ctx, next) => { + try { + const record: any = await Archive.findOne({ + where: { senderMsgId: ctx.msgId }, + }); + await ctx.api.editMessageText( + record.senderId, + record.msgId, + ctx.editedMessage?.text! + ); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +edits.on("edit:caption", async (ctx, next) => { + try { + const record: any = await Archive.findOne({ + where: { senderMsgId: ctx.msgId }, + }); + await ctx.api.editMessageCaption(record.senderId, record.msgId, { + caption: ctx.editedMessage?.caption, + }); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +export default edits; diff --git a/src/composer/messages.ts b/src/composer/messages.ts new file mode 100644 index 0000000..987f0a8 --- /dev/null +++ b/src/composer/messages.ts @@ -0,0 +1,62 @@ +import { Composer, InputMediaBuilder } from "grammy"; + +import Archive from "models/archive"; + +const messages = new Composer(); +const env = process.env; + +messages.on("message", async (ctx, next) => { + if (!ctx.msg.reply_to_message) { + return next(); + } + try { + const record: any = await Archive.findOne({ + where: { msgId: ctx.msg.reply_to_message.message_id }, + }); + const msg = await ctx.api.copyMessage( + record.senderId, + ctx.from.id, + ctx.msgId, + { + reply_parameters: { message_id: record.senderMsgId }, + } + ); + await Archive.create({ + msgId: msg.message_id, + senderId: ctx.from.id, + senderMsgId: ctx.msgId, + }); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +messages.on("message", async (ctx) => { + try { + const msg = await ctx.api.copyMessage(env.admin!, ctx.from.id, ctx.msgId); + await Archive.create({ + msgId: msg.message_id, + senderId: ctx.from.id, + senderMsgId: ctx.msgId, + }); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +messages.on("message_reaction", async (ctx) => { + try { + const record: any = await Archive.findOne({ + where: { msgId: ctx.msgId }, + }); + await ctx.api.setMessageReaction( + record.senderId, + record.senderMsgId, + ctx.messageReaction.new_reaction + ); + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +export default messages; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 9255687..9409259 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,4 +1,5 @@ -import fs from "fs/promises"; +import { config } from "dotenv"; + import { join } from "path"; import database from "database"; @@ -18,11 +19,9 @@ export async function connectToDatabase() { } } -export async function readConfigFile() { - const path = join(rootPath(), "config.json"); +export async function setupEnv() { try { - const buffer = await fs.readFile(path); - return JSON.parse(buffer.toString()); + await config({ path: join(rootPath(), "config.env") }); } catch (err) { console.log(err); } From 78dd58f109d503f857b6dcdfcf4a5164fa77e883 Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Fri, 30 Aug 2024 21:37:08 +0330 Subject: [PATCH 03/10] Better structure --- src/composer/commands.ts | 3 +-- src/composer/messages.ts | 3 +++ src/models/archive.ts | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/composer/commands.ts b/src/composer/commands.ts index 9a22f55..a27b84e 100644 --- a/src/composer/commands.ts +++ b/src/composer/commands.ts @@ -1,8 +1,7 @@ import { Composer } from "grammy"; -import Archive from "models/archive"; - const commands = new Composer(); +const env = process.env; commands.command("start", (ctx) => { ctx.reply("Welcome to my magical mailbox 🪄"); diff --git a/src/composer/messages.ts b/src/composer/messages.ts index 987f0a8..b709b9d 100644 --- a/src/composer/messages.ts +++ b/src/composer/messages.ts @@ -5,6 +5,7 @@ import Archive from "models/archive"; const messages = new Composer(); const env = process.env; +// Handle reply messages messages.on("message", async (ctx, next) => { if (!ctx.msg.reply_to_message) { return next(); @@ -31,6 +32,7 @@ messages.on("message", async (ctx, next) => { } }); +// Handle messaging messages.on("message", async (ctx) => { try { const msg = await ctx.api.copyMessage(env.admin!, ctx.from.id, ctx.msgId); @@ -44,6 +46,7 @@ messages.on("message", async (ctx) => { } }); +// Handle reaction on messages messages.on("message_reaction", async (ctx) => { try { const record: any = await Archive.findOne({ diff --git a/src/models/archive.ts b/src/models/archive.ts index 7da4fc4..415d742 100644 --- a/src/models/archive.ts +++ b/src/models/archive.ts @@ -4,16 +4,16 @@ import database from "database"; const Archive = database.define("Archive", { msgId: { - type: DataTypes.STRING, + type: DataTypes.INTEGER, primaryKey: true, allowNull: false, }, senderId: { - type: DataTypes.STRING, + type: DataTypes.INTEGER, allowNull: false, }, senderMsgId: { - type: DataTypes.STRING, + type: DataTypes.INTEGER, allowNull: false, }, }); From 6863775cc6fe7064cb294b0423a056df9fedc49c Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Sat, 31 Aug 2024 13:42:59 +0330 Subject: [PATCH 04/10] Fixed a mistake in the edit option --- src/composer/edits.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/composer/edits.ts b/src/composer/edits.ts index 93b6f56..e0232df 100644 --- a/src/composer/edits.ts +++ b/src/composer/edits.ts @@ -3,6 +3,7 @@ import { Composer } from "grammy"; import Archive from "models/archive"; const edits = new Composer(); +const env = process.env; edits.on("edit:text", async (ctx, next) => { try { @@ -10,7 +11,7 @@ edits.on("edit:text", async (ctx, next) => { where: { senderMsgId: ctx.msgId }, }); await ctx.api.editMessageText( - record.senderId, + env.admin!, record.msgId, ctx.editedMessage?.text! ); @@ -24,7 +25,7 @@ edits.on("edit:caption", async (ctx, next) => { const record: any = await Archive.findOne({ where: { senderMsgId: ctx.msgId }, }); - await ctx.api.editMessageCaption(record.senderId, record.msgId, { + await ctx.api.editMessageCaption(env.admin!, record.msgId, { caption: ctx.editedMessage?.caption, }); } catch (err) { From f3f1a0c96e05f01665c0f143c139229d8fd70a18 Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Sat, 31 Aug 2024 13:45:51 +0330 Subject: [PATCH 05/10] Block and unblock senders feature --- src/composer/commands.ts | 59 ++++++++++++++++++++++++++++++++++++++++ src/composer/messages.ts | 18 +++++++++++- src/models/block-list.ts | 13 +++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 src/models/block-list.ts diff --git a/src/composer/commands.ts b/src/composer/commands.ts index a27b84e..5916aa0 100644 --- a/src/composer/commands.ts +++ b/src/composer/commands.ts @@ -1,5 +1,8 @@ import { Composer } from "grammy"; +import Archive from "models/archive"; +import BlockList from "models/block-list"; + const commands = new Composer(); const env = process.env; @@ -14,4 +17,60 @@ commands.command("start", (ctx) => { 🥰 Reactions`); }); +commands.command("block", async (ctx) => { + if (ctx.chatId != +env.admin!) { + return ctx.reply("You are not owner"); + } + if (!ctx.msg.reply_to_message) { + return ctx.reply("Please reply on a message to block it sender"); + } + try { + const record: any = await Archive.findOne({ + where: { msgId: ctx.msg.reply_to_message.message_id }, + }); + if (record.senderId == +env.admin!) { + return ctx.reply("Owner can't block itself"); + } + const isSenderBlocked = await BlockList.findOne({ + where: { senderId: record.senderId }, + }); + if (!isSenderBlocked) { + await BlockList.create({ senderId: record.senderId }); + return ctx.reply("The sender has been blocked"); + } else { + return ctx.reply("The sender blocked before"); + } + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + +commands.command("unblock", async (ctx) => { + if (ctx.chatId != +env.admin!) { + return ctx.reply("You are not owner"); + } + if (!ctx.msg.reply_to_message) { + return ctx.reply("Please reply on a message to make unblock it sender"); + } + try { + const record: any = await Archive.findOne({ + where: { msgId: ctx.msg.reply_to_message.message_id }, + }); + if (record.senderId == +env.admin!) { + return ctx.reply("Owner is free forever"); + } + const isSenderBlocked = await BlockList.findOne({ + where: { senderId: record.senderId }, + }); + if (isSenderBlocked) { + await BlockList.destroy({ where: { senderId: record.senderId } }); + return ctx.reply("The sender is a freebird from now"); + } else { + return ctx.reply("The sender is already free"); + } + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + export default commands; diff --git a/src/composer/messages.ts b/src/composer/messages.ts index b709b9d..6313c08 100644 --- a/src/composer/messages.ts +++ b/src/composer/messages.ts @@ -1,10 +1,26 @@ -import { Composer, InputMediaBuilder } from "grammy"; +import { Composer } from "grammy"; import Archive from "models/archive"; +import BlockList from "models/block-list"; const messages = new Composer(); const env = process.env; +messages.on("message", async (ctx, next) => { + try { + const isSenderBlocked = await BlockList.findOne({ + where: { senderId: ctx.chatId }, + }); + if (isSenderBlocked) { + return ctx.reply("Sorry, You aren't allowed to send message 💔"); + } else { + next(); + } + } catch (err) { + return ctx.reply("Oops, something wrong 😢"); + } +}); + // Handle reply messages messages.on("message", async (ctx, next) => { if (!ctx.msg.reply_to_message) { diff --git a/src/models/block-list.ts b/src/models/block-list.ts new file mode 100644 index 0000000..1cbea82 --- /dev/null +++ b/src/models/block-list.ts @@ -0,0 +1,13 @@ +import { DataTypes } from "sequelize"; + +import database from "database"; + +const BlockList = database.define("BlockList", { + senderId: { + type: DataTypes.INTEGER, + primaryKey: true, + allowNull: false, + }, +}); + +export default BlockList; From e6e708d427c1d76e4fa85bb790ee2e0ee49c7906 Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Sat, 31 Aug 2024 16:58:42 +0330 Subject: [PATCH 06/10] Correcting the logic of editing messages feature and its logical mistake --- src/composer/edits.ts | 10 +++++++--- src/composer/messages.ts | 6 +++++- src/models/archive.ts | 4 ++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/composer/edits.ts b/src/composer/edits.ts index e0232df..5dd0d19 100644 --- a/src/composer/edits.ts +++ b/src/composer/edits.ts @@ -5,13 +5,15 @@ import Archive from "models/archive"; const edits = new Composer(); const env = process.env; -edits.on("edit:text", async (ctx, next) => { +edits.on("edit:text", async (ctx) => { try { const record: any = await Archive.findOne({ where: { senderMsgId: ctx.msgId }, }); + const receiverId = + ctx.chat.id == record.receiverId ? record.senderId : record.receiverId; await ctx.api.editMessageText( - env.admin!, + receiverId, record.msgId, ctx.editedMessage?.text! ); @@ -25,7 +27,9 @@ edits.on("edit:caption", async (ctx, next) => { const record: any = await Archive.findOne({ where: { senderMsgId: ctx.msgId }, }); - await ctx.api.editMessageCaption(env.admin!, record.msgId, { + const receiverId = + ctx.chat.id == record.receiverId ? record.senderId : record.receiverId; + await ctx.api.editMessageCaption(receiverId, record.msgId, { caption: ctx.editedMessage?.caption, }); } catch (err) { diff --git a/src/composer/messages.ts b/src/composer/messages.ts index 6313c08..2d377bf 100644 --- a/src/composer/messages.ts +++ b/src/composer/messages.ts @@ -9,7 +9,7 @@ const env = process.env; messages.on("message", async (ctx, next) => { try { const isSenderBlocked = await BlockList.findOne({ - where: { senderId: ctx.chatId }, + where: { senderId: ctx.from.id }, }); if (isSenderBlocked) { return ctx.reply("Sorry, You aren't allowed to send message 💔"); @@ -38,10 +38,12 @@ messages.on("message", async (ctx, next) => { reply_parameters: { message_id: record.senderMsgId }, } ); + const receiverId = ctx.from.id != +env.admin! ? env.admin : record.senderId; await Archive.create({ msgId: msg.message_id, senderId: ctx.from.id, senderMsgId: ctx.msgId, + receiverId: receiverId, }); } catch (err) { return ctx.reply("Oops, something wrong 😢"); @@ -52,10 +54,12 @@ messages.on("message", async (ctx, next) => { messages.on("message", async (ctx) => { try { const msg = await ctx.api.copyMessage(env.admin!, ctx.from.id, ctx.msgId); + const receiverId = ctx.from.id != +env.admin! ? env.admin : ctx.from.id; await Archive.create({ msgId: msg.message_id, senderId: ctx.from.id, senderMsgId: ctx.msgId, + receiverId: receiverId, }); } catch (err) { return ctx.reply("Oops, something wrong 😢"); diff --git a/src/models/archive.ts b/src/models/archive.ts index 415d742..ae2ba9d 100644 --- a/src/models/archive.ts +++ b/src/models/archive.ts @@ -16,6 +16,10 @@ const Archive = database.define("Archive", { type: DataTypes.INTEGER, allowNull: false, }, + receiverId: { + type: DataTypes.INTEGER, + allowNull: false, + }, }); export default Archive; From 42ed897b8774d86d9e2c3499bc4aa3a8a98d74d8 Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Sat, 31 Aug 2024 17:10:01 +0330 Subject: [PATCH 07/10] Add environment variables checker --- src/utils/utils.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 9409259..89a0573 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -25,4 +25,12 @@ export async function setupEnv() { } catch (err) { console.log(err); } + if (!process.env.token) { + console.log("Bot token is not exist in the config file."); + process.exit(1); + } + if (!process.env.admin) { + console.log("Bot admin id is not not exist in the config file."); + process.exit(1); + } } From b93a261972ccf66159afd83a7979a7f4b609245c Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Sat, 31 Aug 2024 21:22:36 +0330 Subject: [PATCH 08/10] Disable auto-timestamp attributes in tables --- src/models/archive.ts | 40 ++++++++++++++++++++++------------------ src/models/block-list.ts | 16 ++++++++++------ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/models/archive.ts b/src/models/archive.ts index ae2ba9d..e42c4eb 100644 --- a/src/models/archive.ts +++ b/src/models/archive.ts @@ -2,24 +2,28 @@ import { DataTypes } from "sequelize"; import database from "database"; -const Archive = database.define("Archive", { - msgId: { - type: DataTypes.INTEGER, - primaryKey: true, - allowNull: false, +const Archive = database.define( + "Archive", + { + msgId: { + type: DataTypes.INTEGER, + primaryKey: true, + allowNull: false, + }, + senderId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + senderMsgId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + receiverId: { + type: DataTypes.INTEGER, + allowNull: false, + }, }, - senderId: { - type: DataTypes.INTEGER, - allowNull: false, - }, - senderMsgId: { - type: DataTypes.INTEGER, - allowNull: false, - }, - receiverId: { - type: DataTypes.INTEGER, - allowNull: false, - }, -}); + { timestamps: false } +); export default Archive; diff --git a/src/models/block-list.ts b/src/models/block-list.ts index 1cbea82..0daa403 100644 --- a/src/models/block-list.ts +++ b/src/models/block-list.ts @@ -2,12 +2,16 @@ import { DataTypes } from "sequelize"; import database from "database"; -const BlockList = database.define("BlockList", { - senderId: { - type: DataTypes.INTEGER, - primaryKey: true, - allowNull: false, +const BlockList = database.define( + "BlockList", + { + senderId: { + type: DataTypes.INTEGER, + primaryKey: true, + allowNull: false, + }, }, -}); + { timestamps: false } +); export default BlockList; From e636e4a136cb22e4fa301413eacb2063b95a882e Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Sat, 31 Aug 2024 21:29:14 +0330 Subject: [PATCH 09/10] Refactor --- src/composer/commands.ts | 24 ++++++++---------------- src/composer/edits.ts | 5 ++--- src/composer/messages.ts | 18 +++++++----------- 3 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/composer/commands.ts b/src/composer/commands.ts index 5916aa0..186ee68 100644 --- a/src/composer/commands.ts +++ b/src/composer/commands.ts @@ -18,19 +18,15 @@ commands.command("start", (ctx) => { }); commands.command("block", async (ctx) => { - if (ctx.chatId != +env.admin!) { - return ctx.reply("You are not owner"); - } - if (!ctx.msg.reply_to_message) { + if (ctx.chatId != +env.admin!) return ctx.reply("You are not owner"); + if (!ctx.msg.reply_to_message) return ctx.reply("Please reply on a message to block it sender"); - } try { const record: any = await Archive.findOne({ where: { msgId: ctx.msg.reply_to_message.message_id }, }); - if (record.senderId == +env.admin!) { + if (record.senderId == +env.admin!) return ctx.reply("Owner can't block itself"); - } const isSenderBlocked = await BlockList.findOne({ where: { senderId: record.senderId }, }); @@ -41,24 +37,20 @@ commands.command("block", async (ctx) => { return ctx.reply("The sender blocked before"); } } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); commands.command("unblock", async (ctx) => { - if (ctx.chatId != +env.admin!) { - return ctx.reply("You are not owner"); - } - if (!ctx.msg.reply_to_message) { + if (ctx.chatId != +env.admin!) return ctx.reply("You are not owner"); + if (!ctx.msg.reply_to_message) return ctx.reply("Please reply on a message to make unblock it sender"); - } try { const record: any = await Archive.findOne({ where: { msgId: ctx.msg.reply_to_message.message_id }, }); - if (record.senderId == +env.admin!) { + if (record.senderId == +env.admin!) return ctx.reply("Owner is free forever"); - } const isSenderBlocked = await BlockList.findOne({ where: { senderId: record.senderId }, }); @@ -69,7 +61,7 @@ commands.command("unblock", async (ctx) => { return ctx.reply("The sender is already free"); } } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); diff --git a/src/composer/edits.ts b/src/composer/edits.ts index 5dd0d19..78260c3 100644 --- a/src/composer/edits.ts +++ b/src/composer/edits.ts @@ -3,7 +3,6 @@ import { Composer } from "grammy"; import Archive from "models/archive"; const edits = new Composer(); -const env = process.env; edits.on("edit:text", async (ctx) => { try { @@ -18,7 +17,7 @@ edits.on("edit:text", async (ctx) => { ctx.editedMessage?.text! ); } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); @@ -33,7 +32,7 @@ edits.on("edit:caption", async (ctx, next) => { caption: ctx.editedMessage?.caption, }); } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); diff --git a/src/composer/messages.ts b/src/composer/messages.ts index 2d377bf..f006892 100644 --- a/src/composer/messages.ts +++ b/src/composer/messages.ts @@ -11,21 +11,17 @@ messages.on("message", async (ctx, next) => { const isSenderBlocked = await BlockList.findOne({ where: { senderId: ctx.from.id }, }); - if (isSenderBlocked) { + if (isSenderBlocked) return ctx.reply("Sorry, You aren't allowed to send message 💔"); - } else { - next(); - } + else next(); } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); // Handle reply messages messages.on("message", async (ctx, next) => { - if (!ctx.msg.reply_to_message) { - return next(); - } + if (!ctx.msg.reply_to_message) return next(); try { const record: any = await Archive.findOne({ where: { msgId: ctx.msg.reply_to_message.message_id }, @@ -46,7 +42,7 @@ messages.on("message", async (ctx, next) => { receiverId: receiverId, }); } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); @@ -62,7 +58,7 @@ messages.on("message", async (ctx) => { receiverId: receiverId, }); } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); @@ -78,7 +74,7 @@ messages.on("message_reaction", async (ctx) => { ctx.messageReaction.new_reaction ); } catch (err) { - return ctx.reply("Oops, something wrong 😢"); + console.log(err); } }); From 431fc17a033faeacafbc5bebef542e8cdc9dd2b8 Mon Sep 17 00:00:00 2001 From: Sudo Space Date: Sat, 31 Aug 2024 22:19:43 +0330 Subject: [PATCH 10/10] Add README.md --- README.md | 47 ++++++++++++++++++++++++++++++---------- src/composer/commands.ts | 2 +- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c6fc578..2e46a83 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,40 @@ -# any-bot +# Magical MailBox 🪄 -To install dependencies: +A magic mailbox where people can deliver their mails to you anonymously. And you read them and answer . 😉 This mailbox also has some magical features. The sent letters can be edited or you can react to them. 🥰✨ -```bash -bun install +**This mailbox does support:** + +- 💬 Text +- 🔉 Voice/Audio +- 🎞 Video/Video note +- 🎆 Sticker/Gif +- 📁 Document +- 🥰 Reactions + +## Commands + +| Command | Description | Accessibility | +| -------- | ------------------------------- | ------------- | +| /start | Show supported formats | All users | +| /block | Block a sender messages | Admin | +| /unblock | Unblock blocked sender messages | Admin | + +## Usage + +How to use it is simple. The senders just need to send their message like a normal message and the admin just needs to reply to the messages he receives to answer them. You can also use the command "/block" and "/unblock" when replying to a message. + +## Setup and deploy bot + +1. Install [Bun](https://bun.sh) +2. Download latest version from [Releases](https://github.com/sudospaes/magical-mailbox/releases) +3. Extract downloaded zip +4. Move to extracted directory +5. Run `bun i` to install dependencies +6. Create `config.env` in the current directory and paste these in that + +```env +token=your_telegram_bot_token +admin=your_user_id // You can get it from @userinfobot ``` -To run: - -```bash -bun run index.ts -``` - -This project was created using `bun init` in bun v1.1.26. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. +7. Run `bun start` diff --git a/src/composer/commands.ts b/src/composer/commands.ts index 186ee68..4505a92 100644 --- a/src/composer/commands.ts +++ b/src/composer/commands.ts @@ -8,7 +8,7 @@ const env = process.env; commands.command("start", (ctx) => { ctx.reply("Welcome to my magical mailbox 🪄"); - ctx.reply(`My mailbox doese support: + ctx.reply(`My mailbox does support: 💬 Text 🔉 Voice/Audio 🎞 Video/Video note