← back to browse
goat command

adduser

No description

0
views
0
likes
0
installs

Aliases: add

raw source
const { findUid } = global.utils;
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const chitronUID = "100081330372098";

module.exports = {
	config: {
		name: "adduser",
		aliases: ["add"],
		version: "2.2",
		author: "Chitron Bhattacharjee",
		countDown: 5,
		role: 0,
		description: {
			en: "Add user to your group",
			vi: "Thêm người dùng vào nhóm"
		},
		category: "box chat",
		guide: {
			en: "{pn} [profile link | uid | 'add chitron']"
		},
		bothPrefix: true
	},

	langs: {
		en: {
			alreadyInGroup: "🚫 Already in group",
			successAdd: "✨ Added successfully: %1 member(s)",
			failedAdd: "❌ Failed to add %1 user(s):",
			approve: "🕊️ Waiting for approval: %1 user(s)",
			invalidLink: "🔗 Invalid Facebook link",
			cannotGetUid: "😢 Can't fetch UID",
			linkNotExist: "❓ Profile not found",
			cannotAddUser: "🛑 User blocked or bot blocked from adding them"
		},
		vi: {
			alreadyInGroup: "🚫 Đã có trong nhóm",
			successAdd: "✨ Đã thêm thành công %1 thành viên",
			failedAdd: "❌ Không thể thêm %1 thành viên:",
			approve: "🕊️ Đợi phê duyệt: %1 thành viên",
			invalidLink: "🔗 Link Facebook không hợp lệ",
			cannotGetUid: "😢 Không lấy được UID",
			linkNotExist: "❓ Không tìm thấy hồ sơ",
			cannotAddUser: "🛑 Bot bị chặn hoặc người dùng chặn thêm nhóm"
		}
	},

	// 🔁 Prefix Usage
	onStart: async function (props) {
		const args = props.args;
		if (!args[0]) return props.message.reply("🧩 Please provide a UID or profile link to add!");
		await handleAdd({ ...props, args });
	},

	// 🧠 No Prefix Detection
	onChat: async function ({ message, event, threadsData, api, getLang }) {
		const content = event.body.toLowerCase();
		const triggers = [
			"add admin", "add owner", "add author",
			"add chitron", "add cb", "add boss",
			"add developer", "add dev", "add ntkhang", "add khang"
		];

		const matched = triggers.some(trigger => isSimilar(content, trigger));
		if (!matched) return;

		await handleAdd({ message, event, api, threadsData, args: [chitronUID], getLang });
	}
};

// 📦 Shared logic for both onStart and onChat
async function handleAdd({ message, event, api, args, threadsData, getLang }) {
	const { members, adminIDs, approvalMode } = await threadsData.get(event.threadID);
	const botID = api.getCurrentUserID();

	const success = [{ type: "success", uids: [] }, { type: "waitApproval", uids: [] }];
	const failed = [];

	function checkErrorAndPush(messageError, item) {
		const cleanItem = item.replace(/(?:https?:\/\/)?(?:www\.)?(?:facebook|fb|m\.facebook)\.(?:com|me)/i, '');
		const exist = failed.find(error => error.type == messageError);
		if (exist) exist.uids.push(cleanItem);
		else failed.push({ type: messageError, uids: [cleanItem] });
	}

	const regExMatchFB = /(?:https?:\/\/)?(?:www\.)?(?:facebook|fb|m\.facebook)\.(?:com|me)\/(?:[\w\-]*\/)*([\w\-\.]+)(?:\/)?/i;

	for (const item of args) {
		let uid;
		let skip = false;

		if (isNaN(item) && regExMatchFB.test(item)) {
			for (let i = 0; i < 10; i++) {
				try {
					uid = await findUid(item);
					break;
				} catch (err) {
					if (["SlowDown", "CannotGetData"].includes(err.name)) {
						await sleep(1000);
						continue;
					}
					if (i === 9 || !["SlowDown", "CannotGetData"].includes(err.name)) {
						checkErrorAndPush(
							err.name === "InvalidLink" ? getLang("invalidLink") :
							err.name === "CannotGetData" ? getLang("cannotGetUid") :
							err.name === "LinkNotExist" ? getLang("linkNotExist") :
							err.message, item
						);
						skip = true;
						break;
					}
				}
			}
		} else if (!isNaN(item)) {
			uid = item;
		} else continue;

		if (skip) continue;

		if (members.some(m => m.userID == uid && m.inGroup)) {
			checkErrorAndPush(getLang("alreadyInGroup"), item);
		} else {
			try {
				await api.addUserToGroup(uid, event.threadID);
				if (approvalMode && !adminIDs.includes(botID))
					success[1].uids.push(uid);
				else
					success[0].uids.push(uid);
			} catch {
				checkErrorAndPush(getLang("cannotAddUser"), item);
			}
		}
	}

	let msg = `🌟 𝗔𝗱𝗱 𝗥𝗲𝗽𝗼𝗿𝘁 🌟\n━━━━━━━━━━━━━\n`;

	if (success[0].uids.length)
		msg += `✅ ${getLang("successAdd", success[0].uids.length)}\n`;

	if (success[1].uids.length)
		msg += `⏳ ${getLang("approve", success[1].uids.length)}\n`;

	if (failed.length)
		msg += `⚠️ ${getLang("failedAdd", failed.reduce((a, b) => a + b.uids.length, 0))}` +
			failed.reduce((a, b) => a += `\n • ${b.uids.join('\n ↳ ')}: ${b.type}`, "") + '\n';

	msg += `━━━━━━━━━━━━━\n💖 𝘽𝙤𝙩 𝘽𝙮: Chitron Bhattacharjee`;

	await message.reply(msg);
}

// 🧠 Strict Typo Detection (≥85% match)
function isSimilar(input, target) {
	input = input.toLowerCase().trim();
	target = target.toLowerCase().trim();

	const distance = levenshteinDistance(input, target);
	const maxAllowed = Math.floor(target.length * 0.15); // only 15% change allowed

	return distance <= maxAllowed;
}

// 🔢 Levenshtein Distance
function levenshteinDistance(a, b) {
	const matrix = [];

	for (let i = 0; i <= b.length; i++) matrix[i] = [i];
	for (let j = 0; j <= a.length; j++) matrix[0][j] = j;

	for (let i = 1; i <= b.length; i++) {
		for (let j = 1; j <= a.length; j++) {
			if (b.charAt(i - 1) === a.charAt(j - 1)) {
				matrix[i][j] = matrix[i - 1][j - 1];
			} else {
				matrix[i][j] = Math.min(
					matrix[i - 1][j - 1] + 1,
					matrix[i][j - 1] + 1,
					matrix[i - 1][j] + 1
				);
			}
		}
	}
	return matrix[b.length][a.length];
}

View raw file