- Мар
- 143
- 34
Пользователь
Помогите мне пж, не могу сделать систему кика в /sysban 2 уровня
Пыталюст сделать чтобы при /sysban @user 2(ур) [дней] [причина] он исключал человека из всех бесед где есть бот, но у меня не получается сделать) помогите сделать
Пыталюст сделать чтобы при /sysban @user 2(ур) [дней] [причина] он исключал человека из всех бесед где есть бот, но у меня не получается сделать) помогите сделать
Код:
const database = require('../databases.js');
const { checkSysAccess, getAccessLevelName } = require('./sysadmin.js');
const { hasCommandAccess, getAccessDeniedMessage } = require('../utils/commandAccess.js');
const { extractNumericId } = require('../utils/userUtils.js');
const vk = require('../vkInstance.js');
const util = require('util');
const fs = require('fs');
const path = require('path');
const databaseQuery = util.promisify(database.query);
const SYSBANNED_FILE = path.join(__dirname, '../data/sysbanned.json');
// Хранилище для отслеживания частоты использования команды
const commandUsage = new Map();
// Кэш забаненных пользователей для быстрой проверки
const bannedUsersCache = new Map();
const CACHE_UPDATE_INTERVAL = 60000; // Обновление кэша каждую минуту
// Функция обновления кэша забаненных пользователей
async function updateBannedUsersCache() {
try {
const now = Math.floor(Date.now() / 1000);
const query = 'SELECT userid, time, level FROM sysbanned WHERE level = 2 AND (time = 0 OR time > ?)';
const results = await databaseQuery(query, [now]);
bannedUsersCache.clear();
results.forEach(row => {
bannedUsersCache.set(Number(row.userid), {
level: row.level,
time: row.time
});
});
console.log(`[SYSBAN] Кэш забаненных обновлен: ${bannedUsersCache.size} пользователей`);
} catch (error) {
console.error('[SYSBAN] Ошибка обновления кэша:', error);
}
}
// Обновляем кэш при старте и каждую минуту
updateBannedUsersCache();
setInterval(updateBannedUsersCache, CACHE_UPDATE_INTERVAL);
function isLevel2Banned(userId) {
if (!fs.existsSync(SYSBANNED_FILE)) return false;
const data = JSON.parse(fs.readFileSync(SYSBANNED_FILE, 'utf-8'));
const now = Math.floor(Date.now() / 1000);
const ban = data.find(u => u.userid === userId && u.level === 2 && (u.time === 0 || u.time > now));
return !!ban;
}
// Функция для проверки лимита использования команды
function checkCommandLimit(userId) {
const now = Date.now();
const userUsage = commandUsage.get(userId) || { count: 0, lastReset: now, blockedUntil: 0 };
// Проверяем, не заблокирован ли пользователь
if (userUsage.blockedUntil > now) {
const minutesLeft = Math.ceil((userUsage.blockedUntil - now) / 60000);
return {
allowed: false,
message: `❌ Превышен лимит использования команды. Попробуйте через ${minutesLeft} мин.`
};
}
// Сбрасываем счетчик, если прошло больше 10 минут с последнего сброса
if (now - userUsage.lastReset > 600000) { // 10 минут в миллисекундах
userUsage.count = 0;
userUsage.lastReset = now;
}
// Увеличиваем счетчик
userUsage.count++;
// Если использовано 3 раза подряд, блокируем на 10 минут
if (userUsage.count >= 3) {
userUsage.blockedUntil = now + 600000; // 10 минут
userUsage.count = 0;
commandUsage.set(userId, userUsage);
return {
allowed: false,
message: '❌ Превышен лимит использования команды. Команда заблокирована на 10 минут.'
};
}
commandUsage.set(userId, userUsage);
return { allowed: true };
}
// Улучшенная функция для кика пользователя из всех бесед
async function kickUserFromAllChats(userId) {
try {
// Получаем список всех бесед, где есть бот
const conversations = await vk.api.messages.getConversations({
count: 200,
});
let kickedCount = 0;
const errors = [];
const kickPromises = [];
for (const item of conversations.items) {
const peerId = item.conversation.peer.id;
// Только беседы
if (peerId <= 2000000000) {
continue;
}
// Беседа отключена
if (
item.conversation.chat_settings?.state === 'disabled'
) {
continue;
}
// Нет настроек беседы = мёртвый чат
if (!item.conversation.chat_settings) {
continue;
}
// Бот не может писать
if (
item.conversation.can_write &&
item.conversation.can_write.allowed === false
) {
continue;
}
// Сразу пытаемся кикнуть
const kickPromise = vk.api.messages.removeChatUser({
chat_id: peerId - 2000000000,
user_id: userId
})
.then(() => {
kickedCount++;
console.log(
`[SYSBAN] Пользователь ${userId} кикнут из беседы ${peerId}`
);
})
.catch(error => {
// Игнорируем недоступные беседы
if (
error.code === 945 ||
error.message?.includes('Chat was disabled')
) {
return;
}
// Пользователя уже нет
if (
error.code === 935 ||
error.message?.includes('User not in chat')
) {
return;
}
const errorMsg =
`Ошибка при кике из беседы ${peerId}: ${error.message}`;
console.error(`[SYSBAN] ${errorMsg}`);
errors.push(errorMsg);
});
kickPromises.push(kickPromise);
}
// Ждем завершения всех операций кика
await Promise.allSettled(kickPromises);
return { kickedCount, errors };
} catch (error) {
console.error('[SYSBAN] Ошибка при кике пользователя из всех бесед:', error);
return { kickedCount: 0, errors: [error.message] };
}
}
// Функция для автоматического кика при попытке добавить в беседу
async function setupAutoKick() {
try {
// Слушаем новые сообщения о добавлении в беседу
const eventHandler = async (event) => {
if (event.type === 'message_new') {
const message = event.object.message;
// Проверяем, что это действие с беседой
if (message.action && message.action.type === 'chat_invite_user') {
const invitedUserId = message.action.member_id;
// Быстрая проверка по кэшу
if (bannedUsersCache.has(invitedUserId)) {
console.log(`[SYSBAN] Обнаружена попытка добавить забаненного пользователя ${invitedUserId} в беседу ${message.peer_id}`);
// Немедленно кикаем
try {
await vk.api.messages.removeChatUser({
chat_id: message.peer_id - 2000000000,
user_id: invitedUserId
});
console.log(`[SYSBAN] Забаненный пользователь ${invitedUserId} автоматически кикнут из беседы ${message.peer_id}`);
// Отправляем уведомление в беседу
await vk.api.messages.send({
peer_id: message.peer_id,
message: `🚫 Пользователь [id${invitedUserId}|заблокирован] в системе бота и не может быть добавлен в беседы.`,
random_id: Math.floor(Math.random() * 1e9),
disable_mentions: true
});
} catch (kickError) {
console.error(`[SYSBAN] Ошибка при автоматическом кике:`, kickError);
}
}
}
}
};
// Подключаем обработчик (способ подключения зависит от вашей архитектуры)
// vk.updates.on('message_new', eventHandler);
console.log('[SYSBAN] Автоматический кик настроен');
} catch (error) {
console.error('[SYSBAN] Ошибка настройки авто-кика:', error);
}
}
// Запускаем авто-кик
setupAutoKick();
// Очистка старых записей раз в час
setInterval(() => {
const now = Date.now();
for (const [userId, data] of commandUsage.entries()) {
if (data.blockedUntil < now && now - data.lastReset > 3600000) { // если блокировка прошла и прошёл час
commandUsage.delete(userId);
}
}
}, 3600000); // Каждый час
module.exports = {
command: '/sysban',
description: 'Блокировка пользователя в системе бота (2 степени)',
async execute(context) {
try {
// Проверка лимита использования
const limitCheck = checkCommandLimit(context.senderId);
if (!limitCheck.allowed) {
return context.reply(limitCheck.message);
}
const hasAccess = await hasCommandAccess(context.senderId, 'sysban');
if (!hasAccess) return context.reply(getAccessDeniedMessage('sysban'));
const args = context.text.split(' ');
if (args.length < 4) return context.reply('❌ Использование:\n/sysban [ID] [1|2] [дни|0] [причина]');
const userId = await extractNumericId(args[1]);
if (!userId) return context.reply('❌ Ошибка | Некорректный ID пользователя');
if (userId === context.senderId) return context.reply('❌ Ошибка | Нельзя заблокировать самого себя');
if (global.botId && Number(userId) === Number(global.botId)) return context.reply('🤖 Нельзя заблокировать бота');
const senderAccess = await checkSysAccess(context.senderId);
let targetAccess = 0;
try { targetAccess = await checkSysAccess(userId); } catch {}
if (targetAccess >= senderAccess && targetAccess > 0) {
return context.reply(`❌ Ошибка | Вы не можете заблокировать пользователя с уровнем "${getAccessLevelName(targetAccess)}"`);
}
const banLevel = parseInt(args[2]);
if (![1, 2].includes(banLevel)) return context.reply('❌ Уровень ЧСБ может быть только 1 или 2');
const banDays = parseInt(args[3]);
if (isNaN(banDays) || banDays < 0) return context.reply('❌ Некорректный срок блокировки');
const reason = args.slice(4).join(' ') || 'Не указана';
const now = Math.floor(Date.now() / 1000);
const endTime = banDays === 0 ? 0 : now + banDays * 86400;
const query = `
INSERT INTO sysbanned (userid, time, reason, who, level)
VALUES (?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE
time = VALUES(time),
reason = VALUES(reason),
who = VALUES(who),
level = VALUES(level)
`;
await databaseQuery(query, [userId, endTime, reason, context.senderId, banLevel]);
// Обновляем кэш сразу после бана
if (banLevel === 2) {
bannedUsersCache.set(Number(userId), {
level: 2,
time: endTime
});
}
let userDisplay = `@id${userId}`;
try {
const u = (await vk.api.users.get({ user_ids: userId }))[0];
if (u) userDisplay = `[id${userId}|${u.first_name} ${u.last_name}]`;
} catch {}
const banType = banLevel === 1 ? '🚫 Запрет команд' : '⛔ Полный запрет бота';
let message = `🚨 ${userDisplay} заблокирован в системе бота\n\n`;
message += `🔐 Тип: ${banType}\n`;
message += `🕒 Срок: ${banDays === 0 ? 'Навсегда' : banDays + ' дн.'}\n`;
message += `📝 Причина: ${reason}`;
await context.send({ message, disable_mentions: true });
try {
await vk.api.messages.send({
peer_id: userId,
message,
random_id: Math.floor(Math.random() * 1e9),
disable_mentions: true
});
} catch {}
// Если это полный запрет (уровень 2), кикаем пользователя из всех бесед
if (banLevel === 2) {
const { kickedCount, errors } = await kickUserFromAllChats(userId);
// Отправляем подробное сообщение о результате кика
let kickMessage = '';
if (kickedCount > 0) {
kickMessage = `👢 Пользователь ${userDisplay} был кикнут из ${kickedCount} бесед`;
} else {
kickMessage = `⚠️ Пользователь ${userDisplay} не был найден в беседах`;
}
if (errors.length > 0) {
kickMessage += `\n\n❌ Ошибки (${errors.length}):\n`;
// Показываем только первые 3 ошибки
errors.slice(0, 3).forEach(err => {
kickMessage += `• ${err}\n`;
});
}
await context.send({
message: kickMessage,
disable_mentions: true
});
// Запускаем дополнительную проверку через 5 секунд
// (на случай, если пользователь был онлайн и не сразу кикнулся)
setTimeout(async () => {
console.log(`[SYSBAN] Повторная проверка пользователя ${userId} через 5 секунд`);
const { kickedCount: additionalKicks } = await kickUserFromAllChats(userId);
if (additionalKicks > 0) {
await context.send({
message: `👢 Дополнительно кикнуто из ${additionalKicks} бесед (повторная проверка)`,
disable_mentions: true
});
}
}, 5000);
}
// Сбрасываем счетчик после успешного выполнения
const userUsage = commandUsage.get(context.senderId);
if (userUsage) {
userUsage.count = 0;
userUsage.lastReset = Date.now();
commandUsage.set(context.senderId, userUsage);
}
} catch (error) {
console.error('SYSBAN ERROR:', error);
context.reply('❌ Ошибка выполнения sysban');
}
}
};
// Экспортируем кэш для использования в других модулях
module.exports.bannedUsersCache = bannedUsersCache;
module.exports.isUserBanned = (userId) => bannedUsersCache.has(Number(userId));