updateenlistmentdata
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
config/
|
config/
|
||||||
data/
|
data/notificationHistory.json
|
||||||
|
data/ipdaeData.json
|
||||||
.env
|
.env
|
||||||
src/commands/admin/
|
src/commands/admin/
|
||||||
src/commands/general/
|
src/commands/general/
|
||||||
|
182
src/data/dataManager.js
Normal file
182
src/data/dataManager.js
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
const { binarySearch, binaryInsert } = require('../utils/helpers');
|
||||||
|
const fs = require('fs').promises;
|
||||||
|
const logger = require('../../modules/colorfulLogger');
|
||||||
|
const {
|
||||||
|
ipdaeDataDirectory,
|
||||||
|
celebrationConfigPath,
|
||||||
|
notificationHistoryPath,
|
||||||
|
dataDir
|
||||||
|
} = require('../../config/constants');
|
||||||
|
|
||||||
|
let ipdaeDatas = [];
|
||||||
|
let celebrationConfig = {};
|
||||||
|
let notificationHistory = {};
|
||||||
|
|
||||||
|
async function loadData() {
|
||||||
|
try {
|
||||||
|
await fs.mkdir(dataDir, { recursive: true });
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Failed to create data directory ${dataDir}: ${e.message}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = await fs.readFile(ipdaeDataDirectory, 'utf8');
|
||||||
|
ipdaeDatas = JSON.parse(data);
|
||||||
|
ipdaeDatas.sort((a, b) => a.id.localeCompare(b.id));
|
||||||
|
logger.info('ipdaeData.json loaded and parsed.');
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(`Failed to load ipdaeData.json: ${e.message}. Initializing as empty array.`);
|
||||||
|
ipdaeDatas = [];
|
||||||
|
if (e.code === 'ENOENT') {
|
||||||
|
await saveData('ipdae');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const historyData = await fs.readFile(notificationHistoryPath, 'utf8');
|
||||||
|
notificationHistory = JSON.parse(historyData);
|
||||||
|
logger.info('notificationHistory.json loaded and parsed.');
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(`notificationHistory.json not found or invalid: ${e.message}. Initializing as empty object.`);
|
||||||
|
notificationHistory = {};
|
||||||
|
if (e.code === 'ENOENT') {
|
||||||
|
await saveData('history');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await migrateData();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const configData = await fs.readFile(celebrationConfigPath, 'utf8');
|
||||||
|
celebrationConfig = JSON.parse(configData);
|
||||||
|
if (celebrationConfig.milestones && Array.isArray(celebrationConfig.milestones)) {
|
||||||
|
celebrationConfig.milestones.forEach(m => {
|
||||||
|
m.mentionUser = m.mentionUser ?? true;
|
||||||
|
m.mentionEveryone = m.mentionEveryone ?? false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new Error("Milestones data is missing or invalid in celebrationConfig.json");
|
||||||
|
}
|
||||||
|
logger.info('celebrationConfig.json loaded and parsed.');
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn(`celebrationConfig.json error: ${e.message}. Creating/Using default config.`);
|
||||||
|
celebrationConfig = {
|
||||||
|
channelTopicKeyword: "전역축하알림",
|
||||||
|
milestones: [
|
||||||
|
{ days: 100, message: "🎉 {userName}님, 전역까지 D-100일! 영광의 그날까지 파이팅입니다! 🎉", mentionUser: true, mentionEveryone: false },
|
||||||
|
{ days: 50, message: "🥳 {userName}님, 전역까지 D-50일! 이제 절반의 고지를 넘었습니다! 🥳", mentionUser: true, mentionEveryone: false },
|
||||||
|
{ days: 30, message: "🗓️ {userName}님, 전역까지 D-30일! 한 달 뒤면 자유의 몸! 🗓️", mentionUser: true, mentionEveryone: false },
|
||||||
|
{ days: 7, message: "✨ {userName}님, 전역까지 D-7일! 일주일만 버티면 됩니다! ✨", mentionUser: true, mentionEveryone: false },
|
||||||
|
{ days: 1, message: "🚀 {userName}님, 드디어 내일 전역입니다! 사회로 나갈 준비 되셨나요? 🚀", mentionUser: true, mentionEveryone: false },
|
||||||
|
{ days: 0, message: "🫡 {userName}님, 🎉축 전역🎉 대한민국의 자랑스러운 아들! 그동안 정말 고 생 많으셨습니다! 🫡", mentionUser: true, mentionEveryone: true }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
await saveData('config');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function migrateData() {
|
||||||
|
let ipdaeDataNeedsSave = false;
|
||||||
|
let notificationHistoryNeedsSave = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < ipdaeDatas.length; i++) {
|
||||||
|
const user = ipdaeDatas[i];
|
||||||
|
if (user.hasOwnProperty('notifiedMilestones')) {
|
||||||
|
if (Array.isArray(user.notifiedMilestones) && user.notifiedMilestones.length > 0) {
|
||||||
|
if (!notificationHistory[user.id] || Object.keys(notificationHistory[user.id]).length === 0) {
|
||||||
|
notificationHistory[user.id] = [...user.notifiedMilestones];
|
||||||
|
notificationHistoryNeedsSave = true;
|
||||||
|
logger.info(`Migrated notifiedMilestones for user ${user.id} to notificationHistory.`);
|
||||||
|
} else {
|
||||||
|
logger.info(`User ${user.id} already has data in notificationHistory.json. Old notifiedMilestones removed.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete user.notifiedMilestones;
|
||||||
|
ipdaeDataNeedsSave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipdaeDataNeedsSave) {
|
||||||
|
await saveData('ipdae');
|
||||||
|
}
|
||||||
|
if (notificationHistoryNeedsSave) {
|
||||||
|
await saveData('history');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveData(type) {
|
||||||
|
try {
|
||||||
|
switch (type) {
|
||||||
|
case 'ipdae':
|
||||||
|
await fs.writeFile(ipdaeDataDirectory, JSON.stringify(ipdaeDatas, null, 4), 'utf8');
|
||||||
|
logger.info('ipdaeData.json saved.');
|
||||||
|
break;
|
||||||
|
case 'config':
|
||||||
|
await fs.writeFile(celebrationConfigPath, JSON.stringify(celebrationConfig, null, 4), 'utf8');
|
||||||
|
logger.info('celebrationConfig.json saved.');
|
||||||
|
break;
|
||||||
|
case 'history':
|
||||||
|
await fs.writeFile(notificationHistoryPath, JSON.stringify(notificationHistory, null, 4), 'utf8');
|
||||||
|
logger.info('notificationHistory.json saved.');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.warn(`Unknown data type for saving: ${type}`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Error saving ${type} data: ${e.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getIpdaeData() {
|
||||||
|
return ipdaeDatas;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCelebrationConfig() {
|
||||||
|
return celebrationConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getNotificationHistory() {
|
||||||
|
return notificationHistory;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateEnlistmentData(userId, date, type) {
|
||||||
|
let notificationHistoryModified = false;
|
||||||
|
const index = binarySearch(ipdaeDatas, userId);
|
||||||
|
|
||||||
|
if (index !== -1) {
|
||||||
|
const oldDate = ipdaeDatas[index].date;
|
||||||
|
const oldType = ipdaeDatas[index].type;
|
||||||
|
|
||||||
|
ipdaeDatas[index].date = date;
|
||||||
|
ipdaeDatas[index].type = type;
|
||||||
|
|
||||||
|
if (oldDate !== date || oldType !== type) {
|
||||||
|
logger.info(`Enlistment data changed for ${userId}. Resetting their notification history.`);
|
||||||
|
notificationHistory[userId] = [];
|
||||||
|
notificationHistoryModified = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
binaryInsert(ipdaeDatas, { id: userId, date: date, type: type });
|
||||||
|
notificationHistory[userId] = [];
|
||||||
|
notificationHistoryModified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
await saveData('ipdae');
|
||||||
|
if (notificationHistoryModified) {
|
||||||
|
await saveData('history');
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipdaeDatas[binarySearch(ipdaeDatas, userId)];
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
loadData,
|
||||||
|
saveData,
|
||||||
|
getIpdaeData,
|
||||||
|
getCelebrationConfig,
|
||||||
|
getNotificationHistory,
|
||||||
|
updateEnlistmentData,
|
||||||
|
ipdaeDatas,
|
||||||
|
celebrationConfig,
|
||||||
|
notificationHistory
|
||||||
|
};
|
Reference in New Issue
Block a user