v5.7
Test public pve
This commit is contained in:
parent
7813a7cde0
commit
d0dbf635ec
12
bot.js
12
bot.js
@ -23,7 +23,8 @@ const {
|
||||
SaleModel,
|
||||
ResourcePriceModel,
|
||||
SkillsModel,
|
||||
DailyModel
|
||||
DailyModel,
|
||||
logMiddleware
|
||||
} = global.config
|
||||
const bot = new Telegraf(process.env.BOT_TOKEN)
|
||||
const rpg = require('./rpg'); // Подключение RPG-механик
|
||||
@ -76,7 +77,6 @@ bot.telegram.setMyCommands([{
|
||||
description: "Создать жалобу/обращение/идею."
|
||||
}
|
||||
])
|
||||
|
||||
bot.use(stage.middleware())
|
||||
bot.use(rpg)
|
||||
|
||||
@ -211,11 +211,19 @@ bot.command('start', async (ctx) => {
|
||||
['🎁 Бонус'],
|
||||
['📦 Контейнеры'],
|
||||
['📢 Вакансии', '🔵 Имущество', '📞 Пригласить'],
|
||||
['🛡️ Test'],
|
||||
])
|
||||
.resize()
|
||||
)
|
||||
})
|
||||
|
||||
bot.hears('🛡️ Test', async (ctx) => {
|
||||
const buttons = [
|
||||
[Markup.button.callback('PVE', 'locations')],
|
||||
];
|
||||
ctx.reply(`🚨 Добро пожаловать в тестовый режим 🚨\nВесь функционал в этом режиме еще не сбалансирован\n`, Markup.inlineKeyboard(buttons));
|
||||
})
|
||||
|
||||
bot.hears('Криминал', async (ctx) => {
|
||||
await ctx.scene.enter('Crime')
|
||||
})
|
||||
|
@ -57,4 +57,6 @@ module.exports = {
|
||||
343500, 349550, 355650, 361800, 368000
|
||||
],
|
||||
topSym : ['🥇', '🥈', '🥉', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣', '🔟', '🌫️', '🌫️', '🌫️', '🌫️', '🌫️'],
|
||||
logs: require('../utils/logs'),
|
||||
logMiddleware: require('../utils/logMiddleware'),
|
||||
}
|
1122
json/logs.json
Normal file
1122
json/logs.json
Normal file
File diff suppressed because it is too large
Load Diff
120
rpg.js
120
rpg.js
@ -28,7 +28,8 @@ const {
|
||||
TruckModel,
|
||||
ResourcePriceModel,
|
||||
SkillsModel,
|
||||
DailyModel
|
||||
DailyModel,
|
||||
logs
|
||||
} = global.config
|
||||
const rpg = new Composer();
|
||||
|
||||
@ -37,7 +38,6 @@ rpg.use(async (ctx, next) => {
|
||||
let id = ctx.from.id
|
||||
let username = ctx.from.username;
|
||||
if (username == null) username = ctx.from.id;
|
||||
|
||||
const currentTime = utils.getCurrentTime();
|
||||
|
||||
switch (ctx.updateType) {
|
||||
@ -482,7 +482,6 @@ rpg.action(/brutecard_/, async (ctx) => {
|
||||
if (!emulator) {
|
||||
return ctx.reply('Для запуска брутфорса вам нужен "Эмулятор картридера".');
|
||||
}
|
||||
|
||||
// Удаляем "Эмулятор картридера" из инвентаря
|
||||
await InventoryModel.destroy({ where: { id: emulator.id } });
|
||||
|
||||
@ -519,7 +518,7 @@ rpg.action(/brutecard_/, async (ctx) => {
|
||||
const keyboard = Markup.inlineKeyboard(
|
||||
rows.sort(() => Math.random() - 0.5).map((row) => row) // Сортируем строки кнопок случайным образом
|
||||
);
|
||||
|
||||
logs(ctx, "Брутфорс карты", {card: card, keyboard: keyboard, emulator: emulator});
|
||||
// Отправляем сообщение с клавиатурой
|
||||
await ctx.reply(
|
||||
`💳 Брутфорс карты\n
|
||||
@ -587,6 +586,7 @@ rpg.action(/brute_fail_/, async (ctx) => {
|
||||
const keyboard = Markup.inlineKeyboard(
|
||||
rows.sort(() => Math.random() - 0.5).map((row) => row)
|
||||
);
|
||||
logs(ctx, "Брутфорс карты (Fail)", {card: card, keyboard: keyboard});
|
||||
|
||||
// Обновляем сообщение с клавиатурой
|
||||
await ctx.editMessageText(
|
||||
@ -616,7 +616,7 @@ rpg.action(/brute_success_/, async (ctx) => {
|
||||
delete attempts[ctx.from.id];
|
||||
const amount = card.balance; // Сумма денег за карточку
|
||||
const character = await CharacterModel.findByPk(ctx.from.id);
|
||||
|
||||
logs(ctx, "Брутфорс карты (Success)", {card: card, amount: amount});
|
||||
// Увеличиваем грязные деньги пользователя
|
||||
character.dirtymoney += amount;
|
||||
await character.save();
|
||||
@ -670,6 +670,7 @@ rpg.action(`POCKET_ACTION`, async (ctx) => {
|
||||
if (character.pocketstealcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`);
|
||||
character.pocketstealcd = cooldown.endTime
|
||||
character.stamina -= 10
|
||||
logs(ctx, "Карманная кража (Start)", { cdBefore: pocketsteal, cdAfter: character.pocketstealcd, stamina: character.stamina });
|
||||
character.save()
|
||||
ctx.editMessageText('Выберите объект', Markup.inlineKeyboard([
|
||||
[
|
||||
@ -710,6 +711,7 @@ rpg.action(`MONEY_IN_POCKET`, async (ctx) => {
|
||||
let moneyIn = utils.rand(5, 1000);
|
||||
Exp(ctx, character, character.intelligence + 3)
|
||||
character.dirtymoney += moneyIn;
|
||||
logs(ctx, "Карманная кража (Кошелек)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, moneyIn: moneyIn});
|
||||
await character.save();
|
||||
return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из кармана.`);
|
||||
});
|
||||
@ -735,6 +737,7 @@ rpg.action(`PHONE`, async (ctx) => {
|
||||
return await ctx.reply(`Вы сбыли украденный ${phones[randPhone].name} за Ð${utils.spaces(dirtyMoney)}`)
|
||||
}
|
||||
property.mobile = phones[randPhone]
|
||||
logs(ctx, "Карманная кража (Телефон)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, phone: phones[randPhone]});
|
||||
await character.save()
|
||||
await property.save()
|
||||
return ctx.editMessageText(`Вы успешно украли ${phones[randPhone].name} из кармана.`)
|
||||
@ -763,6 +766,7 @@ rpg.action(`MONEY_IN_WALLET`, async (ctx) => {
|
||||
let moneyIn = utils.rand(1000, 10000)
|
||||
Exp(ctx, character, character.intelligence + 5)
|
||||
character.dirtymoney += moneyIn
|
||||
logs(ctx, "Карманная кража (Бумажник)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, moneyIn: moneyIn});
|
||||
character.save()
|
||||
return ctx.editMessageText(`Вы успешно украли Ð${utils.spaces(moneyIn)} из бумажника.`)
|
||||
});
|
||||
@ -778,7 +782,8 @@ rpg.action(`CARD_IN_WALLET`, async (ctx) => {
|
||||
return ctx.editMessageText('Вы были замечены во время кражи.')
|
||||
}
|
||||
Exp(ctx, character, character.intelligence + 7)
|
||||
generateCard(ctx.from.id)
|
||||
let newCard = generateCard(ctx.from.id)
|
||||
logs(ctx, "Карманная кража (Карта)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, card: newCard});
|
||||
character.save()
|
||||
return ctx.editMessageText(`Вы успешно украли 💳 из бумажника.`)
|
||||
});
|
||||
@ -820,6 +825,7 @@ rpg.action(`POCKET_BAG`, async (ctx) => {
|
||||
}
|
||||
Exp(ctx, character, character.intelligence + times)
|
||||
character.dirtymoney += moneyIn
|
||||
logs(ctx, "Карманная кража (Сумка)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, moneyIn: moneyIn});
|
||||
character.save()
|
||||
return ctx.editMessageText(`Вы успешно украли сумку и сбыли все ценности из нее:\n${text}\nОбщий куш: Ð${utils.spaces(moneyIn)}`)
|
||||
});
|
||||
@ -848,6 +854,7 @@ rpg.action('SHOP_ACTION', async (ctx) => {
|
||||
if (character.shoprobcd > cooldown.currentTime) return ctx.editMessageText(`📛 Данное действие будет доступно через ${cooldown.timeLeftInMinutes} мин.`);
|
||||
character.shoprobcd = cooldown.endTime
|
||||
character.stamina -= 25
|
||||
logs(ctx, "Ограбление магазина (Start)", {cdBefore: shoprobcd, cdAfter: character.shoprobcd, stamina: character.stamina});
|
||||
character.save()
|
||||
return ctx.editMessageText('Стадии:', Markup.inlineKeyboard([
|
||||
[{ text: 'Взлом кассы', callback_data: `SHOP_CASH_BREAK` }],
|
||||
@ -865,6 +872,7 @@ rpg.action(`SHOP_CASH_BREAK`, async (ctx) => {
|
||||
if (chance < randomRoll) {
|
||||
const keyboard = generateKeyboard();
|
||||
ctx.deleteMessage()
|
||||
logs(ctx, "Ограбление магазина (Взлом кассы ручной)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, keyboard: keyboard, cashIn: cashIn});
|
||||
return ctx.reply('Касса закрыта, вы начали взлом замка:', keyboard);
|
||||
//ctx.editMessageText('Вы начали взлом кассы.');
|
||||
//return ctx.scene.enter('LOCKPICK')
|
||||
@ -884,6 +892,7 @@ rpg.action(`SHOP_CASH_BREAK`, async (ctx) => {
|
||||
[{ text: 'Завершить ограбление', callback_data: `SHOP_END` }]
|
||||
]))
|
||||
}, timer + 300)
|
||||
logs(ctx, "Ограбление магазина (Взлом кассы быстро)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, cashIn: cashIn});
|
||||
});
|
||||
|
||||
rpg.action(`SHOP_CASH_SMASH`, async (ctx) => {
|
||||
@ -913,6 +922,7 @@ rpg.action(`SHOP_CASH_SMASH`, async (ctx) => {
|
||||
[{ text: 'Завершить ограбление', callback_data: `SHOP_END` }]
|
||||
]))
|
||||
}, timer + 300)
|
||||
logs(ctx, "Ограбление магазина (Разбитие кассы)", {baseChance: baseChance, chance: chance, randomRoll: randomRoll, cashIn: cashIn});
|
||||
});
|
||||
|
||||
rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => {
|
||||
@ -936,6 +946,7 @@ rpg.action(`SHOP_CASH_BREAK_SUCCESS`, async (ctx) => {
|
||||
[{ text: 'Завершить ограбление', callback_data: `SHOP_END` }]
|
||||
]))
|
||||
}, timer + 300)
|
||||
logs(ctx, "Ограбление магазина (Взлом кассы)", {cashIn: cashIn});
|
||||
});
|
||||
|
||||
rpg.action(`SHOP_END`, async (ctx) => {
|
||||
@ -959,9 +970,10 @@ rpg.action(/lock_*/, async (ctx) => {
|
||||
// Проверяем, не исчерпаны ли попытки
|
||||
if (attempts[userId] >= 5) {
|
||||
delete attempts[userId]; // Сбрасываем попытки после провала
|
||||
logs(ctx, "Взлом замка (Full Fail)", {attempts: attempts[userId]});
|
||||
return ctx.editMessageText('Взлом провалился. Замок остается нетронутым.');
|
||||
}
|
||||
|
||||
logs(ctx, "Взлом замка (Fail)", {attempts: attempts[userId]});
|
||||
// Ответ на нажатие кнопки
|
||||
ctx.answerCbQuery(`Штифт не сдвинулся. Попыток осталось: ${5 - attempts[userId]}`);
|
||||
removeButton(ctx, buttonId);
|
||||
@ -1014,7 +1026,6 @@ rpg.action('inventory', async (ctx) => {
|
||||
),
|
||||
];
|
||||
buttons.push(Markup.button.callback('🔙 В меню', 'crime_menu'));
|
||||
|
||||
await ctx.editMessageText(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
|
||||
} catch (error) {
|
||||
console.error('Ошибка при выводе инвентаря:', error);
|
||||
@ -1048,8 +1059,8 @@ rpg.action(/view_item_(\d+)/, async (ctx) => {
|
||||
if (item.equipped && item.canBeEquipped) {
|
||||
buttons.push([Markup.button.callback(`🚫 Снять ${item.name}`, `unequip_item_${item.id}`)]);
|
||||
}
|
||||
|
||||
await ctx.replyWithMarkdown(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
|
||||
logs(ctx, "Просмотр предмета", {item: item});
|
||||
await ctx.reply(message, Markup.inlineKeyboard(buttons, { columns: 2 }));
|
||||
});
|
||||
|
||||
rpg.action(/use_item_(\d+)/, async (ctx) => {
|
||||
@ -1521,32 +1532,6 @@ const fillEnemies = async () => {
|
||||
console.log("Enemies filled.");
|
||||
};
|
||||
|
||||
const fillLocations = async () => {
|
||||
const locations = [
|
||||
{
|
||||
name: "Заброшенный склад",
|
||||
description: "Темный склад с кучей мусора.",
|
||||
enemies: [1, 2, 3],
|
||||
level: 1,
|
||||
loot: [6, 7],
|
||||
rarity: 1
|
||||
},
|
||||
{
|
||||
name: "Лесопосадка",
|
||||
description: "Густой лес с опасными тропами.",
|
||||
enemies: [2, 3, 4],
|
||||
level: 2,
|
||||
loot: [8, 9],
|
||||
rarity: 2
|
||||
},
|
||||
];
|
||||
|
||||
for (const location of locations) {
|
||||
await Location.create(location);
|
||||
}
|
||||
console.log("Locations filled.");
|
||||
};
|
||||
|
||||
const generateBattles = async () => {
|
||||
const locations = await Location.findAll();
|
||||
|
||||
@ -1592,14 +1577,17 @@ const generateBattles = async () => {
|
||||
|
||||
generateBattles()
|
||||
schedule.scheduleJob('0 * * * *', generateBattles); // Каждый час в начале часа
|
||||
rpg.command("locations", async (ctx) => {
|
||||
|
||||
|
||||
|
||||
rpg.action("locations", async (ctx) => {
|
||||
const locations = await Location.findAll();
|
||||
if (!locations.length) {
|
||||
return ctx.reply("Нет доступных локаций для исследования.");
|
||||
}
|
||||
|
||||
const locationButtons = locations.map((location) => ({
|
||||
text: location.name,
|
||||
text: location.name + ` (${location.level} lvl.)`,
|
||||
callback_data: `viewlocation_${location.id}`,
|
||||
}));
|
||||
|
||||
@ -1628,7 +1616,7 @@ rpg.action(/viewlocation_\d+/, async (ctx) => {
|
||||
[{ text: "Охота", callback_data: `hunt_location_${location.id}` }],
|
||||
]);
|
||||
|
||||
await ctx.reply(description, keyboard);
|
||||
await ctx.editMessageText(description, keyboard);
|
||||
});
|
||||
|
||||
rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
@ -1643,7 +1631,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
if (!character) {
|
||||
return ctx.reply("Ваш персонаж не найден.");
|
||||
}
|
||||
|
||||
logs(ctx, "Охота", {location: location});
|
||||
const inventory = await InventoryModel.findAll({ where: { telegram_id: ctx.from.id } });
|
||||
const hasGrenadeLow = inventory.some((item) => item.text_id === "grenade_low");
|
||||
const hasGrenadeMedium = inventory.some((item) => item.text_id === "grenade_medium");
|
||||
@ -1651,7 +1639,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
|
||||
const enemyIds = location.enemies || [];
|
||||
if (enemyIds.length === 0) {
|
||||
return ctx.reply("В этой локации сейчас нет врагов. Попробуйте позже.");
|
||||
return ctx.answerCbQuery("В этой локации сейчас нет врагов. Попробуйте позже.");
|
||||
}
|
||||
|
||||
const activeBattles = await Battle.findAll({
|
||||
@ -1659,14 +1647,14 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
});
|
||||
|
||||
if (activeBattles.length === 0) {
|
||||
return ctx.reply("В этой локации сейчас нет активных врагов. Попробуйте позже.");
|
||||
return ctx.answerCbQuery("В этой локации сейчас нет активных врагов. Попробуйте позже.");
|
||||
}
|
||||
|
||||
const activeEnemyIds = activeBattles.map((battle) => battle.enemy);
|
||||
const enemies = await Enemy.findAll({ where: { id: activeEnemyIds } });
|
||||
|
||||
if (enemies.length === 0) {
|
||||
return ctx.reply("В этой локации сейчас нет врагов.");
|
||||
return ctx.answerCbQuery("В этой локации сейчас нет врагов.");
|
||||
}
|
||||
|
||||
const buttons = activeBattles.map((battle) => {
|
||||
@ -1686,7 +1674,7 @@ rpg.action(/hunt_location_\d+/, async (ctx) => {
|
||||
|
||||
const keyboard = Markup.inlineKeyboard(buttons.map((btn) => [btn]));
|
||||
|
||||
await ctx.reply(
|
||||
await ctx.editMessageText(
|
||||
`🔍 Локация: ${location.name}\n\nВыберите врага для охоты:`,
|
||||
keyboard
|
||||
);
|
||||
@ -1749,7 +1737,7 @@ rpg.action(/use_grenade_\d+/, async (ctx) => {
|
||||
// Удаляем гранату из инвентаря
|
||||
await InventoryModel.destroy({ where: { id: grenade.id } });
|
||||
|
||||
await ctx.reply(message);
|
||||
await ctx.answerCbQuery(message, { show_alert: true });
|
||||
});
|
||||
|
||||
|
||||
@ -1920,20 +1908,20 @@ function generateBattleButtons(character, battle) {
|
||||
|
||||
// Генерация кнопки с критическим уроном
|
||||
buttons.push({
|
||||
text: `💥`,
|
||||
text: `🎯`,
|
||||
callback_data: `critical_${battle.id}`,
|
||||
});
|
||||
|
||||
// Гарантированная кнопка промаха
|
||||
buttons.push({
|
||||
text: "❌",
|
||||
text: "🎯",
|
||||
callback_data: `miss_${battle.id}`,
|
||||
});
|
||||
|
||||
// Заполнение оставшихся кнопок (если не хватает до totalButtons)
|
||||
while (buttons.length < totalButtons) {
|
||||
buttons.push({
|
||||
text: "❌",
|
||||
text: "🎯",
|
||||
callback_data: `miss_${battle.id}`,
|
||||
});
|
||||
}
|
||||
@ -2055,40 +2043,4 @@ rpg.action(/miss_\d+/, async (ctx) => {
|
||||
|
||||
|
||||
|
||||
const fillItemsTable = async () => {
|
||||
try {
|
||||
const items = [];
|
||||
|
||||
// Генерируем 10 случайных предметов
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const item = {
|
||||
name: fakerRU.commerce.productName(), // Название товара
|
||||
description: fakerRU.lorem.sentence(), // Описание товара
|
||||
price: fakerRU.commerce.price({ dec: 0 }), // Цена товара
|
||||
rarity: 1, // Редкость (от 1 до 5)
|
||||
type: 'other', // Тип предмета
|
||||
};
|
||||
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
// Вставляем все 10 предметов в таблицу
|
||||
await ItemsModel.bulkCreate(items);
|
||||
console.log('Таблица предметов успешно заполнена!');
|
||||
} catch (error) {
|
||||
console.error('Ошибка при заполнении таблицы предметов:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Запускаем функцию
|
||||
//fillItemsTable();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
module.exports = rpg;
|
||||
|
52
utils/logMiddleware.js
Normal file
52
utils/logMiddleware.js
Normal file
@ -0,0 +1,52 @@
|
||||
const fs = require("fs");
|
||||
|
||||
/**
|
||||
* Middleware для логирования всех действий в боте.
|
||||
*/
|
||||
function logMiddleware(ctx, next) {
|
||||
const logEntry = {
|
||||
timestamp: new Date().toISOString(),
|
||||
user: {
|
||||
id: ctx.from?.id || "unknown",
|
||||
username: ctx.from?.username || "unknown",
|
||||
first_name: ctx.from?.first_name || "unknown",
|
||||
last_name: ctx.from?.last_name || "",
|
||||
},
|
||||
chat: ctx.chat ? { id: ctx.chat.id, type: ctx.chat.type } : null,
|
||||
type: ctx.updateType, // Тип обновления (message, callback_query и т.д.)
|
||||
data: getDataFromContext(ctx), // Извлечение данных из контекста
|
||||
};
|
||||
|
||||
const logString = JSON.stringify(logEntry, null, 2);
|
||||
|
||||
// Сохраняем лог в файл
|
||||
fs.appendFile('./json/logs.json', logString + "\n", (err) => {
|
||||
if (err) {
|
||||
console.error("Ошибка при записи лога:", err);
|
||||
}
|
||||
});
|
||||
|
||||
// Вызываем следующий middleware
|
||||
return next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Извлечение данных из контекста (например, текст сообщения или данные кнопки).
|
||||
*/
|
||||
function getDataFromContext(ctx) {
|
||||
if (ctx.message) {
|
||||
return { text: ctx.message.text || "нет текста", message_id: ctx.message.message_id };
|
||||
}
|
||||
|
||||
if (ctx.callbackQuery) {
|
||||
return { data: ctx.callbackQuery.data || "нет данных", id: ctx.callbackQuery.id };
|
||||
}
|
||||
|
||||
if (ctx.inlineQuery) {
|
||||
return { query: ctx.inlineQuery.query || "пустой запрос" };
|
||||
}
|
||||
|
||||
return "неизвестное событие";
|
||||
}
|
||||
|
||||
module.exports = logMiddleware;
|
34
utils/logs.js
Normal file
34
utils/logs.js
Normal file
@ -0,0 +1,34 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
/**
|
||||
* Функция для записи логов.
|
||||
* @param {Object} ctx - Контекст Telegraf (содержит данные о пользователе и сообщении).
|
||||
* @param {String} action - Описание действия, например, "Начало битвы", "Использована граната".
|
||||
* @param {Object} [extraData] - Дополнительные данные для логов.
|
||||
*/
|
||||
function logAction(ctx, action, extraData = {}) {
|
||||
const logEntry = {
|
||||
timestamp: new Date().toISOString(),
|
||||
user: {
|
||||
id: ctx.from.id,
|
||||
username: ctx.from.username || "unknown",
|
||||
first_name: ctx.from.first_name || "unknown",
|
||||
last_name: ctx.from.last_name || "",
|
||||
},
|
||||
chat: ctx.chat ? { id: ctx.chat.id, type: ctx.chat.type } : null,
|
||||
action,
|
||||
extraData,
|
||||
};
|
||||
|
||||
const logString = JSON.stringify(logEntry, null, 2);
|
||||
|
||||
// Сохраняем лог в файл
|
||||
fs.appendFile('./json/logs.json', logString + "\n", (err) => {
|
||||
if (err) {
|
||||
console.error("Ошибка при записи лога:", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = logAction;
|
Loading…
Reference in New Issue
Block a user