mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
* fix: Ensure safe access to agent capabilities in AgentConfig * fix: don't show agent builder if agents endpoint is not enabled * fix: Improve error logging for MCP tool calls * fix: Enhance error message for MCP tool failures * feat: Add optional spec and iconURL properties to TEndpointOption type * chore: Update condition to use constant for new conversation parameter * feat: Enhance abort error handling with additional endpoint options to properly render error message fields * fix: Throw error instead of returning message for failed MCP tool calls * refactor: separate logic to generate new S3 URLs for expired links * feat: Implement S3 URL refresh for user avatars with error handling * fix: authcontext error in chats where agent chain is used * refactor: streamline balance configuration logic in getBalanceConfig function * fix: enhance icon resolution logic in SpecIcon component * fix: allow null values for spec and iconURL in TEndpointOption type * fix: update balance check to allow null tokenCredits
193 lines
6.8 KiB
JavaScript
193 lines
6.8 KiB
JavaScript
const { FileSources } = require('librechat-data-provider');
|
|
const {
|
|
Balance,
|
|
getFiles,
|
|
updateUser,
|
|
deleteFiles,
|
|
deleteConvos,
|
|
deletePresets,
|
|
deleteMessages,
|
|
deleteUserById,
|
|
deleteAllUserSessions,
|
|
} = require('~/models');
|
|
const User = require('~/models/User');
|
|
const { updateUserPluginAuth, deleteUserPluginAuth } = require('~/server/services/PluginService');
|
|
const { updateUserPluginsService, deleteUserKey } = require('~/server/services/UserService');
|
|
const { verifyEmail, resendVerificationEmail } = require('~/server/services/AuthService');
|
|
const { needsRefresh, getNewS3URL } = require('~/server/services/Files/S3/crud');
|
|
const { processDeleteRequest } = require('~/server/services/Files/process');
|
|
const { deleteAllSharedLinks } = require('~/models/Share');
|
|
const { deleteToolCalls } = require('~/models/ToolCall');
|
|
const { Transaction } = require('~/models/Transaction');
|
|
const { logger } = require('~/config');
|
|
|
|
const getUserController = async (req, res) => {
|
|
/** @type {MongoUser} */
|
|
const userData = req.user.toObject != null ? req.user.toObject() : { ...req.user };
|
|
delete userData.totpSecret;
|
|
if (req.app.locals.fileStrategy === FileSources.s3 && userData.avatar) {
|
|
const avatarNeedsRefresh = needsRefresh(userData.avatar, 3600);
|
|
if (!avatarNeedsRefresh) {
|
|
return res.status(200).send(userData);
|
|
}
|
|
const originalAvatar = userData.avatar;
|
|
try {
|
|
userData.avatar = await getNewS3URL(userData.avatar);
|
|
await updateUser(userData.id, { avatar: userData.avatar });
|
|
} catch (error) {
|
|
userData.avatar = originalAvatar;
|
|
logger.error('Error getting new S3 URL for avatar:', error);
|
|
}
|
|
}
|
|
res.status(200).send(userData);
|
|
};
|
|
|
|
const getTermsStatusController = async (req, res) => {
|
|
try {
|
|
const user = await User.findById(req.user.id);
|
|
if (!user) {
|
|
return res.status(404).json({ message: 'User not found' });
|
|
}
|
|
res.status(200).json({ termsAccepted: !!user.termsAccepted });
|
|
} catch (error) {
|
|
logger.error('Error fetching terms acceptance status:', error);
|
|
res.status(500).json({ message: 'Error fetching terms acceptance status' });
|
|
}
|
|
};
|
|
|
|
const acceptTermsController = async (req, res) => {
|
|
try {
|
|
const user = await User.findByIdAndUpdate(req.user.id, { termsAccepted: true }, { new: true });
|
|
if (!user) {
|
|
return res.status(404).json({ message: 'User not found' });
|
|
}
|
|
res.status(200).json({ message: 'Terms accepted successfully' });
|
|
} catch (error) {
|
|
logger.error('Error accepting terms:', error);
|
|
res.status(500).json({ message: 'Error accepting terms' });
|
|
}
|
|
};
|
|
|
|
const deleteUserFiles = async (req) => {
|
|
try {
|
|
const userFiles = await getFiles({ user: req.user.id });
|
|
await processDeleteRequest({
|
|
req,
|
|
files: userFiles,
|
|
});
|
|
} catch (error) {
|
|
logger.error('[deleteUserFiles]', error);
|
|
}
|
|
};
|
|
|
|
const updateUserPluginsController = async (req, res) => {
|
|
const { user } = req;
|
|
const { pluginKey, action, auth, isEntityTool } = req.body;
|
|
let authService;
|
|
try {
|
|
if (!isEntityTool) {
|
|
const userPluginsService = await updateUserPluginsService(user, pluginKey, action);
|
|
|
|
if (userPluginsService instanceof Error) {
|
|
logger.error('[userPluginsService]', userPluginsService);
|
|
const { status, message } = userPluginsService;
|
|
res.status(status).send({ message });
|
|
}
|
|
}
|
|
|
|
if (auth) {
|
|
const keys = Object.keys(auth);
|
|
const values = Object.values(auth);
|
|
if (action === 'install' && keys.length > 0) {
|
|
for (let i = 0; i < keys.length; i++) {
|
|
authService = await updateUserPluginAuth(user.id, keys[i], pluginKey, values[i]);
|
|
if (authService instanceof Error) {
|
|
logger.error('[authService]', authService);
|
|
const { status, message } = authService;
|
|
res.status(status).send({ message });
|
|
}
|
|
}
|
|
}
|
|
if (action === 'uninstall' && keys.length > 0) {
|
|
for (let i = 0; i < keys.length; i++) {
|
|
authService = await deleteUserPluginAuth(user.id, keys[i]);
|
|
if (authService instanceof Error) {
|
|
logger.error('[authService]', authService);
|
|
const { status, message } = authService;
|
|
res.status(status).send({ message });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
res.status(200).send();
|
|
} catch (err) {
|
|
logger.error('[updateUserPluginsController]', err);
|
|
return res.status(500).json({ message: 'Something went wrong.' });
|
|
}
|
|
};
|
|
|
|
const deleteUserController = async (req, res) => {
|
|
const { user } = req;
|
|
|
|
try {
|
|
await deleteMessages({ user: user.id }); // delete user messages
|
|
await deleteAllUserSessions({ userId: user.id }); // delete user sessions
|
|
await Transaction.deleteMany({ user: user.id }); // delete user transactions
|
|
await deleteUserKey({ userId: user.id, all: true }); // delete user keys
|
|
await Balance.deleteMany({ user: user._id }); // delete user balances
|
|
await deletePresets(user.id); // delete user presets
|
|
/* TODO: Delete Assistant Threads */
|
|
await deleteConvos(user.id); // delete user convos
|
|
await deleteUserPluginAuth(user.id, null, true); // delete user plugin auth
|
|
await deleteUserById(user.id); // delete user
|
|
await deleteAllSharedLinks(user.id); // delete user shared links
|
|
await deleteUserFiles(req); // delete user files
|
|
await deleteFiles(null, user.id); // delete database files in case of orphaned files from previous steps
|
|
await deleteToolCalls(user.id); // delete user tool calls
|
|
/* TODO: queue job for cleaning actions and assistants of non-existant users */
|
|
logger.info(`User deleted account. Email: ${user.email} ID: ${user.id}`);
|
|
res.status(200).send({ message: 'User deleted' });
|
|
} catch (err) {
|
|
logger.error('[deleteUserController]', err);
|
|
return res.status(500).json({ message: 'Something went wrong.' });
|
|
}
|
|
};
|
|
|
|
const verifyEmailController = async (req, res) => {
|
|
try {
|
|
const verifyEmailService = await verifyEmail(req);
|
|
if (verifyEmailService instanceof Error) {
|
|
return res.status(400).json(verifyEmailService);
|
|
} else {
|
|
return res.status(200).json(verifyEmailService);
|
|
}
|
|
} catch (e) {
|
|
logger.error('[verifyEmailController]', e);
|
|
return res.status(500).json({ message: 'Something went wrong.' });
|
|
}
|
|
};
|
|
|
|
const resendVerificationController = async (req, res) => {
|
|
try {
|
|
const result = await resendVerificationEmail(req);
|
|
if (result instanceof Error) {
|
|
return res.status(400).json(result);
|
|
} else {
|
|
return res.status(200).json(result);
|
|
}
|
|
} catch (e) {
|
|
logger.error('[verifyEmailController]', e);
|
|
return res.status(500).json({ message: 'Something went wrong.' });
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
getUserController,
|
|
getTermsStatusController,
|
|
acceptTermsController,
|
|
deleteUserController,
|
|
verifyEmailController,
|
|
updateUserPluginsController,
|
|
resendVerificationController,
|
|
};
|