From d046d4327f7d467842eef4ccf1690fa2956d75a7 Mon Sep 17 00:00:00 2001 From: "Bots.Business" Date: Thu, 6 Nov 2025 03:43:20 +0000 Subject: [PATCH] Bots.Business export for bot id: 2800189 --- README.md | 23 +- bot.json | 4 +- commands/@.js | 173 ++++++----- commands/Payment Service/_afterNotify.js | 1 + commands/Payment Service/_cancelRequest.js | 12 - commands/Payment Service/_link.js | 3 + commands/Payment Service/_runTransfer.js | 75 +++++ .../_acceptRequest.js | 16 +- commands/Removed Commands/_cancelRequest.js | 21 ++ .../_onRequest.js | 17 +- .../{ => Removed Commands}/_start-info.js | 6 +- commands/Transfering/_getTransferUrl.js | 1 + commands/Transfering/_setTransferSecret.js | 1 + commands/Transfering/onTransferRequest.js | 1 + commands/Transfering/transfer.js | 272 +++++++++++++----- commands/_.js | 57 +++- commands/_angryPoints.js | 1 + commands/_balance.js | 16 +- commands/_setAngryPoints.js | 3 +- commands/_setup.js | 15 +- commands/_start.js | 106 ++++++- commands/_test.js | 13 + .../\360\237\214\200 Exchange/_doexchange.js" | 1 + .../\360\237\214\200 Exchange/_exchange.js" | 6 +- .../_no-linked-account.js" | 1 + .../\360\237\214\200 Exchange/onexchange.js" | 1 + libs/Random.js | 44 --- libs/commonLib.js | 49 ++-- 28 files changed, 669 insertions(+), 270 deletions(-) delete mode 100644 commands/Payment Service/_cancelRequest.js create mode 100644 commands/Payment Service/_runTransfer.js rename commands/{Payment Service => Removed Commands}/_acceptRequest.js (73%) create mode 100644 commands/Removed Commands/_cancelRequest.js rename commands/{Payment Service => Removed Commands}/_onRequest.js (68%) rename commands/{ => Removed Commands}/_start-info.js (82%) create mode 100644 commands/_test.js delete mode 100644 libs/Random.js diff --git a/README.md b/README.md index bb45da1..2d25946 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,5 @@ -# BBPointBot - chat bot -It is repository for chat bot: [@BBPointBot](https://t.me/BBPointBot) - -I am BB point bot. I am under development.āš’ - -:gem: - it is BB Point. - -You can spend it: -- for iterations -- for discount -- for good help from admin - -All conditions will be later! -Just start collecting thems! - -You can get :gem:: -- for good answer and help in BB chat - -![](https://i.imgur.com/fw7HmsG.png) - - +# NewBBPointBot - chat bot +It is repository for chat bot: [@NewBBPointBot](https://t.me/NewBBPointBot) ## What it is? This repository can be imported to [Bots.Business](https://bots.business) as a worked chat bot. diff --git a/bot.json b/bot.json index 903ae9c..3804e81 100644 --- a/bot.json +++ b/bot.json @@ -1,6 +1,6 @@ { "bb_sync_version":"1.0", - "name":"BBPointBot", + "name":"NewBBPointBot", "csv_url":null, - "git_remote":"git@github.com:bots-business/BBPointBot.git" + "git_remote":"git@github.com:abhijeetpatil2122/BBPointBot" } \ No newline at end of file diff --git a/commands/@.js b/commands/@.js index b0416a2..87fbb2e 100644 --- a/commands/@.js +++ b/commands/@.js @@ -1,95 +1,138 @@ /*CMD command: @ help: - need_reply: + need_reply: false auto_retry_time: folder: - answer: - keyboard: + + <]/g, + t => ({ "&": "&", "<": "<", ">": ">" }[t]) + ) } -function broadcastOperation(amount, from_user, to_user, operation){ - if(amount==0){ return } - - let prefix = "+"; - if(amount<0){ prefix = "-" } - - let name = isAdmin() ? "admin" : Libs.commonLib.getNameFor(from_user); - let other_name = Libs.commonLib.getNameFor(to_user); - if(operation){ operation+= "\n" } - if(!operation){ operation = "" } - broadcastToChanell(operation + name + " > " + other_name + ": " + prefix + amount + "šŸ’Ž"); +// Format a user's display name +function getUserSimpleName(u) { + if (!u) return "Unknown" + if (u.username) return `@${u.username}` + if (u.first_name) return escapeHTML(u.first_name) + if (u.last_name) return escapeHTML(u.last_name) + return "User" } -function transferPoint(){ - res.removeAnyway(1) - anotherRes = Libs.ResourcesLib.anotherUserRes("BBPoint", answer.answer_from_id); - anotherRes.add(1); +// Format current date and time as readable string +function formatTimestamp() { + const now = new Date() + const yyyy = now.getFullYear() + const mm = String(now.getMonth() + 1).padStart(2, "0") + const dd = String(now.getDate()).padStart(2, "0") + const hh = String(now.getHours()).padStart(2, "0") + const min = String(now.getMinutes()).padStart(2, "0") + return `${yyyy}-${mm}-${dd} ${hh}:${min}` } -function showAlert(text){ - Api.answerCallbackQuery({ - callback_query_id: req.request_id, - text: text, - show_alert: true // or false - for alert on top +// Send message to info channel for logs or announcements +function broadcastToChannel(text) { + let channel = + AdminPanel.getFieldValue({ + panel_name: "Options", + field_name: "InfoChannel" + }) || "" + + channel = channel.trim() || "@BBPointBotNew" + + Api.sendMessage({ + chat_id: channel, + text, + parse_mode: "HTML" }) } -function havePointOnRequest(req){ - let res = Libs.ResourcesLib.userRes("BBPoint"); +// Build and broadcast operation details (transfer, punishment, etc.) +function broadcastOperation(amount, from_user, to_user, reason, muteInfo) { + if (!amount || amount === 0) return - if(!res.have(req.amount)){ - showAlert("Not enough šŸ’Ž.\nYou have only: " + - res.value() + "šŸ’Ž"); - return + const prefix = amount > 0 ? "+" : "" + const timestamp = formatTimestamp() + + const fromName = isAdmin() ? "Admin" : getUserSimpleName(from_user) + const toName = getUserSimpleName(to_user) + + let base = `šŸ“… ${timestamp} | ${fromName} > ${toName}: ${prefix}${amount} šŸ’Ž` + + if (muteInfo && amount < 0) { + base += ` (Punishment: ${muteInfo})` + } else if (muteInfo && amount > 0) { + base += ` (Unban: ${muteInfo})` } - return true -} -function parseRequestParams(){ - // we have params like req10-X-points-to-TgID - // return { amount: X, transferred_to_tg_id: Y } - if(params==""){ return } + if (reason && reason.trim() !== "") { + const cleaned = reason.replace(/^-+\s*/, "") + base += `\nšŸ“ Reason: ${escapeHTML(cleaned)}` + } - let arr = params.split("-") - let webhook_url = Bot.getProperty("extUrl_" + arr[0].split("req")[1]); + broadcastToChannel(base) +} +// Display alert popup for callback query +function showAlert(text) { + Api.answerCallbackQuery({ + callback_query_id: + typeof req !== "undefined" && req.request_id ? req.request_id : "", + text, + show_alert: true + }) +} + +// Parse incoming request parameters for webhook data +function parseRequestParams() { + if (!params || params === "") return null + const arr = params.split("-") + const webhook_id = (arr[0] || "").split("req")[1] + const webhook_url = Bot.getProperty("extUrl_" + webhook_id) return { - webhook_url: webhook_url, - amount: parseInt(arr[1]), - transferred_to_tg_id: arr[4], // telegram id - message_id: arr[5], - request_id: arr[6], - // sometime we have JSON parse error winh first_name, last_name - // make json without thems - user: { - id: user.id, - telegramid: user.telegramid, - username: user.username, - language_code: user.language_code, - created_at: user.created_at - } + webhook_url, + amount: parseInt(arr[1], 10), + transferred_to_tg_id: arr[4], + message_id: arr[5], + request_id: arr[6], + user: { + id: user.id, + telegramid: user.telegramid, + username: user.username, + language_code: user.language_code, + created_at: user.created_at + } } } + diff --git a/commands/Payment Service/_afterNotify.js b/commands/Payment Service/_afterNotify.js index 50983bf..f104f29 100644 --- a/commands/Payment Service/_afterNotify.js +++ b/commands/Payment Service/_afterNotify.js @@ -7,6 +7,7 @@ answer: keyboard: aliases: + group: CMD*/ let req = parseRequestParams() // { amount: X, transferred_to_tg_id: Y } diff --git a/commands/Payment Service/_cancelRequest.js b/commands/Payment Service/_cancelRequest.js deleted file mode 100644 index 62bdb83..0000000 --- a/commands/Payment Service/_cancelRequest.js +++ /dev/null @@ -1,12 +0,0 @@ -/*CMD - command: /cancelRequest - help: - need_reply: - auto_retry_time: - folder: Payment Service - answer: - keyboard: - aliases: -CMD*/ - -Api.deleteMessage({ message_id: request.message.message_id }) diff --git a/commands/Payment Service/_link.js b/commands/Payment Service/_link.js index ffc59aa..cda7238 100644 --- a/commands/Payment Service/_link.js +++ b/commands/Payment Service/_link.js @@ -11,8 +11,11 @@ See demo @BBWebhookBot ANSWER keyboard: aliases: + group: CMD*/ +if (chat.chat_type != "private") {return} + let url = message; let lastIndex = Bot.getProperty("lastExternalUrlIndex", 0); diff --git a/commands/Payment Service/_runTransfer.js b/commands/Payment Service/_runTransfer.js new file mode 100644 index 0000000..38af32a --- /dev/null +++ b/commands/Payment Service/_runTransfer.js @@ -0,0 +1,75 @@ +/*CMD + command: /runTransfer + help: + need_reply: false + auto_retry_time: + folder: Payment Service + + <]/g, + t => ({ "&": "&", "<": "<", ">": ">" }[t]) + ) +} + +// Return readable username or fallback +function getUserSimpleName(u) { + if (!u) return "Unknown" + if (u.username) return "@" + u.username + if (u.first_name) return escapeHTML(u.first_name) + return "User" +} + +// Get another user's BBPoint resource +let another_tgid +function getAnotherUserRes(from_id) { + if (!from_id) { + if (options.reply_to_message) from_id = options.reply_to_message.from.id + else if (options.bb_options && options.bb_options.reply_to_message) + from_id = options.bb_options.reply_to_message.from.id } - let prefix = "+"; - if(amount<0){ prefix = "-" } - - name = isAdmin() ? "admin" : Libs.commonLib.getNameFor(user); - let msg = prefix + amount + " šŸ’Ž from " + name + ".\nYou have: " + res.value() + "šŸ’Ž"; + another_tgid = from_id + return Libs.ResourcesLib.anotherUserRes("BBPoint", from_id) +} - let transferred_to = options.reply_to_message.from; - Bot.sendMessage(msg, { reply_to_message_id: to_msg }); +// Calculate restriction duration +function getPunishTime(value) { + const now = Math.floor(Date.now() / 1000) + const durations = { "-1": 8 * 3600, "-3": 24 * 3600, "-5": 7 * 24 * 3600 } + if (value <= -8) return now + 400 * 24 * 3600 + const level = Object.keys(durations) + .reverse() + .find(k => value <= parseInt(k)) + return now + Math.max(level ? durations[level] : 0, 31) +} - broadcastOperation(amount, user, transferred_to); +// Get restriction type description +function getMuteDescription(value) { + if (value <= -8) return "Permanent (manual unmute required)" + if (value <= -5) return "1 week" + if (value <= -3) return "24 hours" + if (value <= -1) return "8 hours" + return null } -function canBeAngry(amount){ - if(isAdmin()){ return true } // admin can be very angry - if(canRemoveByAngryPoints(amount)) {return true} - return amount >= 0 +// Apply restriction on user +function punishUser(value) { + if (value > 0) return + Api.restrictChatMember({ + chat_id: request.chat.id, + user_id: another_tgid, + permissions: { + can_send_messages: false, + can_send_media_messages: false, + can_send_polls: false, + can_send_other_messages: false, + can_add_web_page_previews: false, + can_change_info: false, + can_invite_users: false, + can_pin_messages: false + }, + until_date: getPunishTime(value) + }) } -function transferByUser(res, anotherRes, amount){ - if(!res.have(amount)){ - Bot.sendMessage("Not enough šŸ’Ž.\nYou have only: " + - res.value() + "šŸ’Ž", {is_reply: true}); - return false; +// Remove restriction from user +function unrestrictUser(value) { + if (value < 0) return + Api.restrictChatMember({ + chat_id: request.chat.id, + user_id: another_tgid, + permissions: { + can_send_messages: true, + can_send_media_messages: true, + can_send_polls: true, + can_send_other_messages: true, + can_add_web_page_previews: true, + can_change_info: true, + can_invite_users: true, + can_pin_messages: true + }, + until_date: 0 + }) +} + +// Show punishment details text +function punishInfoText(value) { + const punishments = { + "-1": "8-hour read-only mode", + "-3": "24-hour read-only mode", + "-5": "1-week read-only mode", + "-8": "Permanent restriction" } + const current = Object.keys(punishments) + .reverse() + .find(k => value <= parseInt(k)) + return ( + "āš ļø Restrictions – possible punishments:" + + "\n- 8-hour → -1 BBP" + + "\n- 24-hour → -3 BBP" + + "\n- 1-week → -5 BBP" + + "\n- Permanent → -8 BBP" + + (current + ? `\n\nCurrent: ${punishments[current]}` + : "\n\nāœ… No restrictions.") + ) +} - return res.transferTo(anotherRes, amount); +// Send success message after transfer +function successMessage(res, amount, reason) { + const to_msg = options.reply_to_message + ? options.reply_to_message.message_id + : options.bb_options.reply_to_message.message_id + const prefix = amount > 0 ? "+" : "" + const from = isBotAdmin() ? "Admin" : getUserSimpleName(user) + const transferred_to = ( + options.reply_to_message || options.bb_options.reply_to_message + ).from + + let msg = + `${prefix}${amount} šŸ’Ž from ${from}.\nYou have: ${res.value()}šŸ’Ž` + + (reason ? `\n\nReason: ${escapeHTML(reason)}` : "") + + `\n\n
${punishInfoText(res.value())}
` + + if (amount <= -3) msg += "\n\nšŸ—‘ļø Message deleted due to -3 BBP or more." + + Api.sendMessage({ + text: msg, + parse_mode: "HTML", + reply_parameters: { message_id: to_msg } + }) + if (amount <= -3 && to_msg) Api.deleteMessage({ message_id: to_msg }) + + const muteText = getMuteDescription(res.value()) + broadcastOperation(amount, user, transferred_to, reason, muteText) } -function canRemoveByAngryPoints(removalPoints) { - if (removalPoints > 0) { - return false - } - var angryPointsMaxLimit = Libs.ResourcesLib.userRes("angryPointsMaxLimit") - if (-removalPoints > angryPointsMaxLimit.value()) { - // Master can remove points without exceeding the limit - return false +// Validate permission to do transfer +function canDoTransfer(amount) { + if (isBotAdmin()) return true + + if (isChatAdmin) { + if (amount < -5) { + Bot.sendMessage("āš ļø Chat admins can only punish up to -5 BBP.", { + is_reply: true + }) + return false + } + return true } - var availableAngryPoints = Libs.ResourcesLib.userRes("availableAngryPoints") - if (availableAngryPoints.value() + removalPoints < 0) { - // value will be already negative + if (amount < 0) { + Bot.sendMessage("āš ļø You can only give positive BB Points.", { + is_reply: true + }) return false } - return true -} -function removeAngryPoints(removalPoints) { - var availableAngryPoints = Libs.ResourcesLib.userRes("availableAngryPoints") - availableAngryPoints.add(removalPoints) //removalPoints will be already negative + return true } -function transfer(res, anotherRes, amount){ - if(!canBeAngry(amount)){ return } - - if(isAdmin()){ - return anotherRes.add(amount); - } - if (canRemoveByAngryPoints(amount)){ - removeAngryPoints(amount) - return anotherRes.add(amount) - } - return transferByUser(res, anotherRes, amount); +// Run transfer logic +const amount = options.message ?? options.bb_options.message +const reason = options.reason ?? options.bb_options.reason ?? null +const reply_to = options.reply_to_message ?? options.bb_options.reply_to_message +if (typeof amount === "undefined" || isNaN(amount)) { + Bot.sendMessage("āŒ Invalid amount.", { is_reply: true }) + return } -if(!options){ return } +const anotherRes = getAnotherUserRes(reply_to.from.id) +const res = Libs.ResourcesLib.userRes("BBPoint") -let amount = options.message; -let anotherRes = getAnotherUserRes(); +if (!canDoTransfer(amount)) return -let res = Libs.ResourcesLib.userRes("BBPoint"); -let result = transfer(res, anotherRes, amount); +// Apply transfer based on role +let ok = false +if (isBotAdmin() || isChatAdmin) ok = anotherRes.add(amount) +else ok = res.transferTo(anotherRes, amount) -if(result){ - successMessage(anotherRes, amount); +if (ok) { + options.reply_to_message = reply_to + successMessage(anotherRes, amount, reason) + punishUser(anotherRes.value()) + unrestrictUser(anotherRes.value()) } + diff --git a/commands/_.js b/commands/_.js index 1d70e13..6bcb848 100644 --- a/commands/_.js +++ b/commands/_.js @@ -1,37 +1,68 @@ /*CMD command: * help: - need_reply: + need_reply: false auto_retry_time: folder: - answer: - keyboard: + + <> "+request.message_id) diff --git "a/commands/\360\237\214\200 Exchange/_doexchange.js" "b/commands/\360\237\214\200 Exchange/_doexchange.js" index 8133bf5..9246225 100644 --- "a/commands/\360\237\214\200 Exchange/_doexchange.js" +++ "b/commands/\360\237\214\200 Exchange/_doexchange.js" @@ -13,6 +13,7 @@ Use negative number to exchange ANSWER keyboard: aliases: + group: CMD*/ // it is avaible only for BB Admin diff --git "a/commands/\360\237\214\200 Exchange/_exchange.js" "b/commands/\360\237\214\200 Exchange/_exchange.js" index 6006b21..8baaf1a 100644 --- "a/commands/\360\237\214\200 Exchange/_exchange.js" +++ "b/commands/\360\237\214\200 Exchange/_exchange.js" @@ -4,9 +4,13 @@ need_reply: auto_retry_time: folder: šŸŒ€ Exchange - answer: + + <max){ - Bot.sendMessage('Max must be creater then min'); - return - } - return true; -} - -function rndFloat(min, max){ - if(!verifyMinAndMax(min, max)){ return } - return (Math.random() * (max - min + 1)) + min -} - -function rndInt(min, max){ - if(!verifyMinAndMax(min, max)){ return } - return Math.floor(rndFloat(min, max)) -} - -publish({ - sendMessage: function (messages){ - var err_msg = 'need pass messages array. E.g: ["Hello", "Hi!"]'; - if(!messages){ - Bot.sendMessage(err_msg); - } - if(!messages.length || messages.length==0){ - Bot.sendMessage(err_msg); - } - - let random_int = rndInt(0, messages.length-1); - - Bot.sendMessage(messages[random_int]); - }, - - randomInt: rndInt, - randomFloat: rndFloat -}) \ No newline at end of file diff --git a/libs/commonLib.js b/libs/commonLib.js index 5d62333..f3216f0 100644 --- a/libs/commonLib.js +++ b/libs/commonLib.js @@ -1,20 +1,29 @@ -function getNameFor(member){ - let haveAnyNames = member.username||member.first_name||member.last_name; - if(!haveAnyNames){ return ""} - - if(member.username){ - return "@" + member.username - } - - return member.first_name ? member.first_name : member.last_name -} - -function getLinkFor(member){ - return "[" + getNameFor(member) + "](tg://user?id=" + member.telegramid + ")"; -} - -publish({ - getNameFor: getNameFor, - getLinkFor: getLinkFor -}) - +function getNameFor(member){ + let haveAnyNames = member.username||member.first_name||member.last_name; + if(!haveAnyNames){ return ""} + + if(member.username){ + return "@" + member.username + } + + return member.first_name ? member.first_name : member.last_name +} + +function getLinkFor(member, parse_mode){ + let name = getNameFor(member); + if(name==""){ + name = member.telegramid; + } + + if(!parse_mode){ + return "[" + name + "](tg://user?id=" + member.telegramid + ")"; + } + + return "" + name + ""; +} + +publish({ + getNameFor: getNameFor, + getLinkFor: getLinkFor +}) +