Skip to content

Commit 8a2c92d

Browse files
rubentalstraCopilot
authored andcommitted
🚮 feat: Enhance "Delete User" Script (danny-avila#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 <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent 1753301 commit 8a2c92d

File tree

1 file changed

+94
-28
lines changed

1 file changed

+94
-28
lines changed

config/delete-user.js

Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,116 @@
1+
#!/usr/bin/env node
12
const path = require('path');
23
const mongoose = require(path.resolve(__dirname, '..', 'api', 'node_modules', 'mongoose'));
3-
const { User } = require('@librechat/data-schemas').createModels(mongoose);
4+
const {
5+
User,
6+
Agent,
7+
Assistant,
8+
Balance,
9+
Transaction,
10+
ConversationTag,
11+
Conversation,
12+
Message,
13+
File,
14+
Key,
15+
MemoryEntry,
16+
PluginAuth,
17+
Prompt,
18+
PromptGroup,
19+
Preset,
20+
Session,
21+
SharedLink,
22+
ToolCall,
23+
Token,
24+
} = require('@librechat/data-schemas').createModels(mongoose);
425
require('module-alias')({ base: path.resolve(__dirname, '..', 'api') });
526
const { askQuestion, silentExit } = require('./helpers');
627
const connect = require('./connect');
728

29+
async function gracefulExit(code = 0) {
30+
try {
31+
await mongoose.disconnect();
32+
} catch (err) {
33+
console.error('Error disconnecting from MongoDB:', err);
34+
}
35+
silentExit(code);
36+
}
37+
838
(async () => {
939
await connect();
1040

11-
/**
12-
* Show the welcome / help menu
13-
*/
1441
console.purple('---------------');
15-
console.purple('Deleting a user');
42+
console.purple('Deleting a user and all related data');
1643
console.purple('---------------');
1744

18-
let email = '';
19-
if (process.argv.length >= 3) {
20-
email = process.argv[2];
21-
} else {
22-
email = await askQuestion('Email:');
45+
// 1) Get email
46+
let email = process.argv[2]?.trim();
47+
if (!email) {
48+
email = (await askQuestion('Email:')).trim();
49+
}
50+
51+
// 2) Find user
52+
const user = await User.findOne({ email: email.toLowerCase() });
53+
if (!user) {
54+
console.yellow(`No user found with email "${email}"`);
55+
return gracefulExit(0);
2356
}
24-
let user = await User.findOne({ email: email });
25-
if (user !== null) {
26-
if ((await askQuestion(`Delete user ${user}?`)) === 'y') {
27-
user = await User.findOneAndDelete({ _id: user._id });
28-
if (user !== null) {
29-
console.yellow(`Deleted user ${user}`);
30-
} else {
31-
console.yellow(`Couldn't delete user with email ${email}`);
32-
}
33-
}
34-
} else {
35-
console.yellow(`Didn't find user with email ${email}`);
57+
58+
// 3) Confirm full deletion
59+
const confirmAll = await askQuestion(
60+
`Really delete user ${user.email} (${user._id}) and ALL their data? (y/N)`,
61+
);
62+
if (confirmAll.toLowerCase() !== 'y') {
63+
console.yellow('Aborted.');
64+
return gracefulExit(0);
3665
}
3766

38-
silentExit(0);
39-
})();
67+
// 4) Ask specifically about transactions
68+
const confirmTx = await askQuestion('Also delete all transaction history for this user? (y/N)');
69+
const deleteTx = confirmTx.toLowerCase() === 'y';
4070

41-
process.on('uncaughtException', (err) => {
42-
if (!err.message.includes('fetch failed')) {
43-
console.error('There was an uncaught error:');
44-
console.error(err);
71+
const uid = user._id.toString();
72+
73+
// 5) Build and run deletion tasks
74+
const tasks = [
75+
Agent.deleteMany({ author: uid }),
76+
Assistant.deleteMany({ user: uid }),
77+
Balance.deleteMany({ user: uid }),
78+
ConversationTag.deleteMany({ user: uid }),
79+
Conversation.deleteMany({ user: uid }),
80+
Message.deleteMany({ user: uid }),
81+
File.deleteMany({ user: uid }),
82+
Key.deleteMany({ userId: uid }),
83+
MemoryEntry.deleteMany({ userId: uid }),
84+
PluginAuth.deleteMany({ userId: uid }),
85+
Prompt.deleteMany({ author: uid }),
86+
PromptGroup.deleteMany({ author: uid }),
87+
Preset.deleteMany({ user: uid }),
88+
Session.deleteMany({ user: uid }),
89+
SharedLink.deleteMany({ user: uid }),
90+
ToolCall.deleteMany({ user: uid }),
91+
Token.deleteMany({ userId: uid }),
92+
];
93+
94+
if (deleteTx) {
95+
tasks.push(Transaction.deleteMany({ user: uid }));
96+
}
97+
98+
await Promise.all(tasks);
99+
100+
// 6) Finally delete the user document itself
101+
await User.deleteOne({ _id: uid });
102+
103+
console.green(`✔ Successfully deleted user ${email} and all associated data.`);
104+
if (!deleteTx) {
105+
console.yellow('⚠️ Transaction history was retained.');
45106
}
46107

108+
return gracefulExit(0);
109+
})().catch(async (err) => {
47110
if (!err.message.includes('fetch failed')) {
111+
console.error('There was an uncaught error:');
112+
console.error(err);
113+
await mongoose.disconnect();
48114
process.exit(1);
49115
}
50116
});

0 commit comments

Comments
 (0)