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 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') });
|
||||
const { askQuestion, silentExit } = require('./helpers');
|
||||
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 () => {
|
||||
await connect();
|
||||
|
||||
/**
|
||||
* Show the welcome / help menu
|
||||
*/
|
||||
console.purple('---------------');
|
||||
console.purple('Deleting a user');
|
||||
console.purple('Deleting a user and all related data');
|
||||
console.purple('---------------');
|
||||
|
||||
let email = '';
|
||||
if (process.argv.length >= 3) {
|
||||
email = process.argv[2];
|
||||
} else {
|
||||
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}`);
|
||||
// 1) Get email
|
||||
let email = process.argv[2]?.trim();
|
||||
if (!email) {
|
||||
email = (await askQuestion('Email:')).trim();
|
||||
}
|
||||
|
||||
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')) {
|
||||
console.error('There was an uncaught error:');
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
if (!err.message.includes('fetch failed')) {
|
||||
await mongoose.disconnect();
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue