mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 06:00:56 +02:00
🚮 feat: Enhance "Delete User" Script (#7899)
* 🔧 fix: Enhance user deletion script to allow deep deletion of related data * 🔧 fix: Update user deletion script to confirm deep deletion of transaction history * 🔧 fix: Refactor user deletion script to use graceful exit and ensure deep deletion of related data * Update config/delete-user.js is a good idea Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
3af2666890
commit
b412455e9d
1 changed files with 95 additions and 29 deletions
|
@ -1,50 +1,116 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
|
||||||
const { User } = require('@librechat/data-schemas').createModels(mongoose);
|
const {
|
||||||
|
User,
|
||||||
|
Agent,
|
||||||
|
Assistant,
|
||||||
|
Balance,
|
||||||
|
Transaction,
|
||||||
|
ConversationTag,
|
||||||
|
Conversation,
|
||||||
|
Message,
|
||||||
|
File,
|
||||||
|
Key,
|
||||||
|
MemoryEntry,
|
||||||
|
PluginAuth,
|
||||||
|
Prompt,
|
||||||
|
PromptGroup,
|
||||||
|
Preset,
|
||||||
|
Session,
|
||||||
|
SharedLink,
|
||||||
|
ToolCall,
|
||||||
|
Token,
|
||||||
|
} = require('@librechat/data-schemas').createModels(mongoose);
|
||||||
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
|
||||||
const { askQuestion, silentExit } = require('./helpers');
|
const { askQuestion, silentExit } = require('./helpers');
|
||||||
const connect = require('./connect');
|
const connect = require('./connect');
|
||||||
|
|
||||||
|
async function gracefulExit(code = 0) {
|
||||||
|
try {
|
||||||
|
await mongoose.disconnect();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error disconnecting from MongoDB:', err);
|
||||||
|
}
|
||||||
|
silentExit(code);
|
||||||
|
}
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
await connect();
|
await connect();
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the welcome / help menu
|
|
||||||
*/
|
|
||||||
console.purple('---------------');
|
console.purple('---------------');
|
||||||
console.purple('Deleting a user');
|
console.purple('Deleting a user and all related data');
|
||||||
console.purple('---------------');
|
console.purple('---------------');
|
||||||
|
|
||||||
let email = '';
|
// 1) Get email
|
||||||
if (process.argv.length >= 3) {
|
let email = process.argv[2]?.trim();
|
||||||
email = process.argv[2];
|
if (!email) {
|
||||||
} else {
|
email = (await askQuestion('Email:')).trim();
|
||||||
email = await askQuestion('Email:');
|
|
||||||
}
|
|
||||||
let user = await User.findOne({ email: email });
|
|
||||||
if (user !== null) {
|
|
||||||
if ((await askQuestion(`Delete user ${user}?`)) === 'y') {
|
|
||||||
user = await User.findOneAndDelete({ _id: user._id });
|
|
||||||
if (user !== null) {
|
|
||||||
console.yellow(`Deleted user ${user}`);
|
|
||||||
} else {
|
|
||||||
console.yellow(`Couldn't delete user with email ${email}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.yellow(`Didn't find user with email ${email}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
silentExit(0);
|
// 2) Find user
|
||||||
})();
|
const user = await User.findOne({ email: email.toLowerCase() });
|
||||||
|
if (!user) {
|
||||||
|
console.yellow(`No user found with email "${email}"`);
|
||||||
|
return gracefulExit(0);
|
||||||
|
}
|
||||||
|
|
||||||
process.on('uncaughtException', (err) => {
|
// 3) Confirm full deletion
|
||||||
|
const confirmAll = await askQuestion(
|
||||||
|
`Really delete user ${user.email} (${user._id}) and ALL their data? (y/N)`,
|
||||||
|
);
|
||||||
|
if (confirmAll.toLowerCase() !== 'y') {
|
||||||
|
console.yellow('Aborted.');
|
||||||
|
return gracefulExit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4) Ask specifically about transactions
|
||||||
|
const confirmTx = await askQuestion('Also delete all transaction history for this user? (y/N)');
|
||||||
|
const deleteTx = confirmTx.toLowerCase() === 'y';
|
||||||
|
|
||||||
|
const uid = user._id.toString();
|
||||||
|
|
||||||
|
// 5) Build and run deletion tasks
|
||||||
|
const tasks = [
|
||||||
|
Agent.deleteMany({ author: uid }),
|
||||||
|
Assistant.deleteMany({ user: uid }),
|
||||||
|
Balance.deleteMany({ user: uid }),
|
||||||
|
ConversationTag.deleteMany({ user: uid }),
|
||||||
|
Conversation.deleteMany({ user: uid }),
|
||||||
|
Message.deleteMany({ user: uid }),
|
||||||
|
File.deleteMany({ user: uid }),
|
||||||
|
Key.deleteMany({ userId: uid }),
|
||||||
|
MemoryEntry.deleteMany({ userId: uid }),
|
||||||
|
PluginAuth.deleteMany({ userId: uid }),
|
||||||
|
Prompt.deleteMany({ author: uid }),
|
||||||
|
PromptGroup.deleteMany({ author: uid }),
|
||||||
|
Preset.deleteMany({ user: uid }),
|
||||||
|
Session.deleteMany({ user: uid }),
|
||||||
|
SharedLink.deleteMany({ user: uid }),
|
||||||
|
ToolCall.deleteMany({ user: uid }),
|
||||||
|
Token.deleteMany({ userId: uid }),
|
||||||
|
];
|
||||||
|
|
||||||
|
if (deleteTx) {
|
||||||
|
tasks.push(Transaction.deleteMany({ user: uid }));
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(tasks);
|
||||||
|
|
||||||
|
// 6) Finally delete the user document itself
|
||||||
|
await User.deleteOne({ _id: uid });
|
||||||
|
|
||||||
|
console.green(`✔ Successfully deleted user ${email} and all associated data.`);
|
||||||
|
if (!deleteTx) {
|
||||||
|
console.yellow('⚠️ Transaction history was retained.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return gracefulExit(0);
|
||||||
|
})().catch(async (err) => {
|
||||||
if (!err.message.includes('fetch failed')) {
|
if (!err.message.includes('fetch failed')) {
|
||||||
console.error('There was an uncaught error:');
|
console.error('There was an uncaught error:');
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
await mongoose.disconnect();
|
||||||
|
|
||||||
if (!err.message.includes('fetch failed')) {
|
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue