mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-15 15:08:10 +01:00
🗑️ chore: Remove Deprecated Project Model and Associated Fields (#11773)
* chore: remove projects and projectIds usage * chore: empty line linting * chore: remove isCollaborative property across agent models and related tests - Removed the isCollaborative property from agent models, controllers, and tests, as it is deprecated in favor of ACL permissions. - Updated related validation schemas and data provider types to reflect this change. - Ensured all references to isCollaborative were stripped from the codebase to maintain consistency and clarity.
This commit is contained in:
parent
3398f6a17a
commit
37cc5faff5
41 changed files with 94 additions and 821 deletions
|
|
@ -4,7 +4,6 @@ const { logger } = require('@librechat/data-schemas');
|
|||
const { getCustomEndpointConfig } = require('@librechat/api');
|
||||
const {
|
||||
Tools,
|
||||
SystemRoles,
|
||||
ResourceType,
|
||||
actionDelimiter,
|
||||
isAgentsEndpoint,
|
||||
|
|
@ -12,11 +11,6 @@ const {
|
|||
encodeEphemeralAgentId,
|
||||
} = require('librechat-data-provider');
|
||||
const { mcp_all, mcp_delimiter } = require('librechat-data-provider').Constants;
|
||||
const {
|
||||
removeAgentFromAllProjects,
|
||||
removeAgentIdsFromProject,
|
||||
addAgentIdsToProject,
|
||||
} = require('./Project');
|
||||
const { removeAllPermissions } = require('~/server/services/PermissionService');
|
||||
const { getMCPServerTools } = require('~/server/services/Config');
|
||||
const { Agent, AclEntry, User } = require('~/db/models');
|
||||
|
|
@ -291,22 +285,8 @@ const isDuplicateVersion = (updateData, currentData, versions, actionsHash = nul
|
|||
break;
|
||||
}
|
||||
|
||||
// Special handling for projectIds (MongoDB ObjectIds)
|
||||
if (field === 'projectIds') {
|
||||
const wouldBeIds = wouldBeArr.map((id) => id.toString()).sort();
|
||||
const versionIds = lastVersionArr.map((id) => id.toString()).sort();
|
||||
|
||||
if (!wouldBeIds.every((id, i) => id === versionIds[i])) {
|
||||
isMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Handle arrays of objects
|
||||
else if (
|
||||
wouldBeArr.length > 0 &&
|
||||
typeof wouldBeArr[0] === 'object' &&
|
||||
wouldBeArr[0] !== null
|
||||
) {
|
||||
if (wouldBeArr.length > 0 && typeof wouldBeArr[0] === 'object' && wouldBeArr[0] !== null) {
|
||||
const sortedWouldBe = [...wouldBeArr].map((item) => JSON.stringify(item)).sort();
|
||||
const sortedVersion = [...lastVersionArr].map((item) => JSON.stringify(item)).sort();
|
||||
|
||||
|
|
@ -587,7 +567,6 @@ const removeAgentResourceFiles = async ({ agent_id, files }) => {
|
|||
const deleteAgent = async (searchParameter) => {
|
||||
const agent = await Agent.findOneAndDelete(searchParameter);
|
||||
if (agent) {
|
||||
await removeAgentFromAllProjects(agent.id);
|
||||
await Promise.all([
|
||||
removeAllPermissions({
|
||||
resourceType: ResourceType.AGENT,
|
||||
|
|
@ -631,10 +610,6 @@ const deleteUserAgents = async (userId) => {
|
|||
const agentIds = userAgents.map((agent) => agent.id);
|
||||
const agentObjectIds = userAgents.map((agent) => agent._id);
|
||||
|
||||
for (const agentId of agentIds) {
|
||||
await removeAgentFromAllProjects(agentId);
|
||||
}
|
||||
|
||||
await AclEntry.deleteMany({
|
||||
resourceType: { $in: [ResourceType.AGENT, ResourceType.REMOTE_AGENT] },
|
||||
resourceId: { $in: agentObjectIds },
|
||||
|
|
@ -710,7 +685,6 @@ const getListAgentsByAccess = async ({
|
|||
name: 1,
|
||||
avatar: 1,
|
||||
author: 1,
|
||||
projectIds: 1,
|
||||
description: 1,
|
||||
updatedAt: 1,
|
||||
category: 1,
|
||||
|
|
@ -755,64 +729,6 @@ const getListAgentsByAccess = async ({
|
|||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the projects associated with an agent, adding and removing project IDs as specified.
|
||||
* This function also updates the corresponding projects to include or exclude the agent ID.
|
||||
*
|
||||
* @param {Object} params - Parameters for updating the agent's projects.
|
||||
* @param {IUser} params.user - Parameters for updating the agent's projects.
|
||||
* @param {string} params.agentId - The ID of the agent to update.
|
||||
* @param {string[]} [params.projectIds] - Array of project IDs to add to the agent.
|
||||
* @param {string[]} [params.removeProjectIds] - Array of project IDs to remove from the agent.
|
||||
* @returns {Promise<MongoAgent>} The updated agent document.
|
||||
* @throws {Error} If there's an error updating the agent or projects.
|
||||
*/
|
||||
const updateAgentProjects = async ({ user, agentId, projectIds, removeProjectIds }) => {
|
||||
const updateOps = {};
|
||||
|
||||
if (removeProjectIds && removeProjectIds.length > 0) {
|
||||
for (const projectId of removeProjectIds) {
|
||||
await removeAgentIdsFromProject(projectId, [agentId]);
|
||||
}
|
||||
updateOps.$pullAll = { projectIds: removeProjectIds };
|
||||
}
|
||||
|
||||
if (projectIds && projectIds.length > 0) {
|
||||
for (const projectId of projectIds) {
|
||||
await addAgentIdsToProject(projectId, [agentId]);
|
||||
}
|
||||
updateOps.$addToSet = { projectIds: { $each: projectIds } };
|
||||
}
|
||||
|
||||
if (Object.keys(updateOps).length === 0) {
|
||||
return await getAgent({ id: agentId });
|
||||
}
|
||||
|
||||
const updateQuery = { id: agentId, author: user.id };
|
||||
if (user.role === SystemRoles.ADMIN) {
|
||||
delete updateQuery.author;
|
||||
}
|
||||
|
||||
const updatedAgent = await updateAgent(updateQuery, updateOps, {
|
||||
updatingUserId: user.id,
|
||||
skipVersioning: true,
|
||||
});
|
||||
if (updatedAgent) {
|
||||
return updatedAgent;
|
||||
}
|
||||
if (updateOps.$addToSet) {
|
||||
for (const projectId of projectIds) {
|
||||
await removeAgentIdsFromProject(projectId, [agentId]);
|
||||
}
|
||||
} else if (updateOps.$pull) {
|
||||
for (const projectId of removeProjectIds) {
|
||||
await addAgentIdsToProject(projectId, [agentId]);
|
||||
}
|
||||
}
|
||||
|
||||
return await getAgent({ id: agentId });
|
||||
};
|
||||
|
||||
/**
|
||||
* Reverts an agent to a specific version in its version history.
|
||||
* @param {Object} searchParameter - The search parameters to find the agent to revert.
|
||||
|
|
@ -921,7 +837,6 @@ module.exports = {
|
|||
deleteAgent,
|
||||
deleteUserAgents,
|
||||
revertAgentVersion,
|
||||
updateAgentProjects,
|
||||
countPromotedAgents,
|
||||
addAgentResourceFile,
|
||||
getListAgentsByAccess,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ const {
|
|||
deleteAgent,
|
||||
deleteUserAgents,
|
||||
revertAgentVersion,
|
||||
updateAgentProjects,
|
||||
addAgentResourceFile,
|
||||
getListAgentsByAccess,
|
||||
removeAgentResourceFiles,
|
||||
|
|
@ -1060,53 +1059,6 @@ describe('models/Agent', () => {
|
|||
expect(userAfter.favorites.some((f) => f.model === 'gpt-4')).toBe(true);
|
||||
});
|
||||
|
||||
test('should update agent projects', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
const projectId1 = new mongoose.Types.ObjectId();
|
||||
const projectId2 = new mongoose.Types.ObjectId();
|
||||
const projectId3 = new mongoose.Types.ObjectId();
|
||||
|
||||
await createAgent({
|
||||
id: agentId,
|
||||
name: 'Project Test Agent',
|
||||
provider: 'test',
|
||||
model: 'test-model',
|
||||
author: authorId,
|
||||
projectIds: [projectId1],
|
||||
});
|
||||
|
||||
await updateAgent(
|
||||
{ id: agentId },
|
||||
{ $addToSet: { projectIds: { $each: [projectId2, projectId3] } } },
|
||||
);
|
||||
|
||||
await updateAgent({ id: agentId }, { $pull: { projectIds: projectId1 } });
|
||||
|
||||
await updateAgent({ id: agentId }, { projectIds: [projectId2, projectId3] });
|
||||
|
||||
const updatedAgent = await getAgent({ id: agentId });
|
||||
expect(updatedAgent.projectIds).toHaveLength(2);
|
||||
expect(updatedAgent.projectIds.map((id) => id.toString())).toContain(projectId2.toString());
|
||||
expect(updatedAgent.projectIds.map((id) => id.toString())).toContain(projectId3.toString());
|
||||
expect(updatedAgent.projectIds.map((id) => id.toString())).not.toContain(
|
||||
projectId1.toString(),
|
||||
);
|
||||
|
||||
await updateAgent({ id: agentId }, { projectIds: [] });
|
||||
|
||||
const emptyProjectsAgent = await getAgent({ id: agentId });
|
||||
expect(emptyProjectsAgent.projectIds).toHaveLength(0);
|
||||
|
||||
const nonExistentId = `agent_${uuidv4()}`;
|
||||
await expect(
|
||||
updateAgentProjects({
|
||||
id: nonExistentId,
|
||||
projectIds: [projectId1],
|
||||
}),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
test('should handle ephemeral agent loading', async () => {
|
||||
const agentId = 'ephemeral_test';
|
||||
const endpoint = 'openai';
|
||||
|
|
@ -1178,20 +1130,6 @@ describe('models/Agent', () => {
|
|||
const result = await fn();
|
||||
expect(result).toBe(expected);
|
||||
});
|
||||
|
||||
test('should handle updateAgentProjects with non-existent agent', async () => {
|
||||
const nonExistentId = `agent_${uuidv4()}`;
|
||||
const userId = new mongoose.Types.ObjectId();
|
||||
const projectId = new mongoose.Types.ObjectId();
|
||||
|
||||
const result = await updateAgentProjects({
|
||||
user: { id: userId.toString() },
|
||||
agentId: nonExistentId,
|
||||
projectIds: [projectId.toString()],
|
||||
});
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -1315,7 +1253,6 @@ describe('models/Agent', () => {
|
|||
test('should handle MongoDB operators and field updates correctly', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
const projectId = new mongoose.Types.ObjectId();
|
||||
|
||||
await createAgent({
|
||||
id: agentId,
|
||||
|
|
@ -1331,7 +1268,6 @@ describe('models/Agent', () => {
|
|||
{
|
||||
description: 'Updated description',
|
||||
$push: { tools: 'tool2' },
|
||||
$addToSet: { projectIds: projectId },
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -1339,7 +1275,6 @@ describe('models/Agent', () => {
|
|||
expect(firstUpdate.description).toBe('Updated description');
|
||||
expect(firstUpdate.tools).toContain('tool1');
|
||||
expect(firstUpdate.tools).toContain('tool2');
|
||||
expect(firstUpdate.projectIds.map((id) => id.toString())).toContain(projectId.toString());
|
||||
expect(firstUpdate.versions).toHaveLength(2);
|
||||
|
||||
await updateAgent(
|
||||
|
|
@ -1744,7 +1679,6 @@ describe('models/Agent', () => {
|
|||
test('should handle version comparison with special field types', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
const projectId = new mongoose.Types.ObjectId();
|
||||
|
||||
await createAgent({
|
||||
id: agentId,
|
||||
|
|
@ -1752,7 +1686,6 @@ describe('models/Agent', () => {
|
|||
provider: 'test',
|
||||
model: 'test-model',
|
||||
author: authorId,
|
||||
projectIds: [projectId],
|
||||
model_parameters: { temperature: 0.7 },
|
||||
});
|
||||
|
||||
|
|
@ -2630,7 +2563,6 @@ describe('models/Agent', () => {
|
|||
const authorId = new mongoose.Types.ObjectId();
|
||||
const userId = new mongoose.Types.ObjectId();
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const projectId = new mongoose.Types.ObjectId();
|
||||
|
||||
await createAgent({
|
||||
id: agentId,
|
||||
|
|
@ -2638,7 +2570,6 @@ describe('models/Agent', () => {
|
|||
provider: 'openai',
|
||||
model: 'gpt-4',
|
||||
author: authorId,
|
||||
projectIds: [projectId],
|
||||
});
|
||||
|
||||
const mockReq = { user: { id: userId.toString() } };
|
||||
|
|
@ -2698,7 +2629,6 @@ describe('models/Agent', () => {
|
|||
test('should handle agent creation with all optional fields', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
const projectId = new mongoose.Types.ObjectId();
|
||||
|
||||
const agent = await createAgent({
|
||||
id: agentId,
|
||||
|
|
@ -2711,9 +2641,7 @@ describe('models/Agent', () => {
|
|||
tools: ['tool1', 'tool2'],
|
||||
actions: ['action1', 'action2'],
|
||||
model_parameters: { temperature: 0.8, max_tokens: 1000 },
|
||||
projectIds: [projectId],
|
||||
avatar: 'https://example.com/avatar.png',
|
||||
isCollaborative: true,
|
||||
tool_resources: {
|
||||
file_search: { file_ids: ['file1', 'file2'] },
|
||||
},
|
||||
|
|
@ -2727,9 +2655,7 @@ describe('models/Agent', () => {
|
|||
expect(agent.actions).toEqual(['action1', 'action2']);
|
||||
expect(agent.model_parameters.temperature).toBe(0.8);
|
||||
expect(agent.model_parameters.max_tokens).toBe(1000);
|
||||
expect(agent.projectIds.map((id) => id.toString())).toContain(projectId.toString());
|
||||
expect(agent.avatar).toBe('https://example.com/avatar.png');
|
||||
expect(agent.isCollaborative).toBe(true);
|
||||
expect(agent.tool_resources.file_search.file_ids).toEqual(['file1', 'file2']);
|
||||
});
|
||||
|
||||
|
|
@ -2935,21 +2861,6 @@ describe('models/Agent', () => {
|
|||
expect(finalAgent.name).toBe('Version 4');
|
||||
});
|
||||
|
||||
test('should handle updateAgentProjects error scenarios', async () => {
|
||||
const nonExistentId = `agent_${uuidv4()}`;
|
||||
const userId = new mongoose.Types.ObjectId();
|
||||
const projectId = new mongoose.Types.ObjectId();
|
||||
|
||||
// Test with non-existent agent
|
||||
const result = await updateAgentProjects({
|
||||
user: { id: userId.toString() },
|
||||
agentId: nonExistentId,
|
||||
projectIds: [projectId.toString()],
|
||||
});
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
test('should handle revertAgentVersion properly', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
|
|
@ -3003,8 +2914,6 @@ describe('models/Agent', () => {
|
|||
test('should handle updateAgent with combined MongoDB operators', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
const projectId1 = new mongoose.Types.ObjectId();
|
||||
const projectId2 = new mongoose.Types.ObjectId();
|
||||
|
||||
await createAgent({
|
||||
id: agentId,
|
||||
|
|
@ -3013,7 +2922,6 @@ describe('models/Agent', () => {
|
|||
model: 'test-model',
|
||||
author: authorId,
|
||||
tools: ['tool1'],
|
||||
projectIds: [projectId1],
|
||||
});
|
||||
|
||||
// Use multiple operators in single update - but avoid conflicting operations on same field
|
||||
|
|
@ -3022,14 +2930,6 @@ describe('models/Agent', () => {
|
|||
{
|
||||
name: 'Updated Name',
|
||||
$push: { tools: 'tool2' },
|
||||
$addToSet: { projectIds: projectId2 },
|
||||
},
|
||||
);
|
||||
|
||||
const finalAgent = await updateAgent(
|
||||
{ id: agentId },
|
||||
{
|
||||
$pull: { projectIds: projectId1 },
|
||||
},
|
||||
);
|
||||
|
||||
|
|
@ -3037,11 +2937,7 @@ describe('models/Agent', () => {
|
|||
expect(updatedAgent.name).toBe('Updated Name');
|
||||
expect(updatedAgent.tools).toContain('tool1');
|
||||
expect(updatedAgent.tools).toContain('tool2');
|
||||
expect(updatedAgent.projectIds.map((id) => id.toString())).toContain(projectId2.toString());
|
||||
|
||||
expect(finalAgent).toBeDefined();
|
||||
expect(finalAgent.projectIds.map((id) => id.toString())).not.toContain(projectId1.toString());
|
||||
expect(finalAgent.versions).toHaveLength(3);
|
||||
expect(updatedAgent.versions).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('should handle updateAgent when agent does not exist', async () => {
|
||||
|
|
@ -3315,65 +3211,6 @@ describe('models/Agent', () => {
|
|||
expect(updated2.description).toBe('Another description');
|
||||
});
|
||||
|
||||
test('should skip version creation when skipVersioning option is used', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
const projectId1 = new mongoose.Types.ObjectId();
|
||||
const projectId2 = new mongoose.Types.ObjectId();
|
||||
|
||||
// Create agent with initial projectIds
|
||||
await createAgent({
|
||||
id: agentId,
|
||||
name: 'Test Agent',
|
||||
provider: 'test',
|
||||
model: 'test-model',
|
||||
author: authorId,
|
||||
projectIds: [projectId1],
|
||||
});
|
||||
|
||||
// Share agent using updateAgentProjects (which uses skipVersioning)
|
||||
const shared = await updateAgentProjects({
|
||||
user: { id: authorId.toString() }, // Use the same author ID
|
||||
agentId: agentId,
|
||||
projectIds: [projectId2.toString()],
|
||||
});
|
||||
|
||||
// Should NOT create a new version due to skipVersioning
|
||||
expect(shared.versions).toHaveLength(1);
|
||||
expect(shared.projectIds.map((id) => id.toString())).toContain(projectId1.toString());
|
||||
expect(shared.projectIds.map((id) => id.toString())).toContain(projectId2.toString());
|
||||
|
||||
// Unshare agent using updateAgentProjects
|
||||
const unshared = await updateAgentProjects({
|
||||
user: { id: authorId.toString() },
|
||||
agentId: agentId,
|
||||
removeProjectIds: [projectId1.toString()],
|
||||
});
|
||||
|
||||
// Still should NOT create a new version
|
||||
expect(unshared.versions).toHaveLength(1);
|
||||
expect(unshared.projectIds.map((id) => id.toString())).not.toContain(projectId1.toString());
|
||||
expect(unshared.projectIds.map((id) => id.toString())).toContain(projectId2.toString());
|
||||
|
||||
// Regular update without skipVersioning should create a version
|
||||
const regularUpdate = await updateAgent(
|
||||
{ id: agentId },
|
||||
{ description: 'Updated description' },
|
||||
);
|
||||
|
||||
expect(regularUpdate.versions).toHaveLength(2);
|
||||
expect(regularUpdate.description).toBe('Updated description');
|
||||
|
||||
// Direct updateAgent with MongoDB operators should still create versions
|
||||
const directUpdate = await updateAgent(
|
||||
{ id: agentId },
|
||||
{ $addToSet: { projectIds: { $each: [projectId1] } } },
|
||||
);
|
||||
|
||||
expect(directUpdate.versions).toHaveLength(3);
|
||||
expect(directUpdate.projectIds.length).toBe(2);
|
||||
});
|
||||
|
||||
test('should preserve agent_ids in version history', async () => {
|
||||
const agentId = `agent_${uuidv4()}`;
|
||||
const authorId = new mongoose.Types.ObjectId();
|
||||
|
|
@ -3754,7 +3591,6 @@ function createTestIds() {
|
|||
return {
|
||||
agentId: `agent_${uuidv4()}`,
|
||||
authorId: new mongoose.Types.ObjectId(),
|
||||
projectId: new mongoose.Types.ObjectId(),
|
||||
fileId: uuidv4(),
|
||||
};
|
||||
}
|
||||
|
|
@ -3788,9 +3624,6 @@ function mockFindOneAndUpdateError(errorOnCall = 1) {
|
|||
}
|
||||
|
||||
function generateVersionTestCases() {
|
||||
const projectId1 = new mongoose.Types.ObjectId();
|
||||
const projectId2 = new mongoose.Types.ObjectId();
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'simple field update',
|
||||
|
|
@ -3817,13 +3650,5 @@ function generateVersionTestCases() {
|
|||
update: { tools: ['tool2', 'tool3'] },
|
||||
duplicate: { tools: ['tool2', 'tool3'] },
|
||||
},
|
||||
{
|
||||
name: 'projectIds update',
|
||||
initial: {
|
||||
projectIds: [projectId1],
|
||||
},
|
||||
update: { projectIds: [projectId1, projectId2] },
|
||||
duplicate: { projectIds: [projectId2, projectId1] },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,133 +0,0 @@
|
|||
const { GLOBAL_PROJECT_NAME } = require('librechat-data-provider').Constants;
|
||||
const { Project } = require('~/db/models');
|
||||
|
||||
/**
|
||||
* Retrieve a project by ID and convert the found project document to a plain object.
|
||||
*
|
||||
* @param {string} projectId - The ID of the project to find and return as a plain object.
|
||||
* @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
|
||||
* @returns {Promise<IMongoProject>} A plain object representing the project document, or `null` if no project is found.
|
||||
*/
|
||||
const getProjectById = async function (projectId, fieldsToSelect = null) {
|
||||
const query = Project.findById(projectId);
|
||||
|
||||
if (fieldsToSelect) {
|
||||
query.select(fieldsToSelect);
|
||||
}
|
||||
|
||||
return await query.lean();
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve a project by name and convert the found project document to a plain object.
|
||||
* If the project with the given name doesn't exist and the name is "instance", create it and return the lean version.
|
||||
*
|
||||
* @param {string} projectName - The name of the project to find or create.
|
||||
* @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
|
||||
* @returns {Promise<IMongoProject>} A plain object representing the project document.
|
||||
*/
|
||||
const getProjectByName = async function (projectName, fieldsToSelect = null) {
|
||||
const query = { name: projectName };
|
||||
const update = { $setOnInsert: { name: projectName } };
|
||||
const options = {
|
||||
new: true,
|
||||
upsert: projectName === GLOBAL_PROJECT_NAME,
|
||||
lean: true,
|
||||
select: fieldsToSelect,
|
||||
};
|
||||
|
||||
return await Project.findOneAndUpdate(query, update, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an array of prompt group IDs to a project's promptGroupIds array, ensuring uniqueness.
|
||||
*
|
||||
* @param {string} projectId - The ID of the project to update.
|
||||
* @param {string[]} promptGroupIds - The array of prompt group IDs to add to the project.
|
||||
* @returns {Promise<IMongoProject>} The updated project document.
|
||||
*/
|
||||
const addGroupIdsToProject = async function (projectId, promptGroupIds) {
|
||||
return await Project.findByIdAndUpdate(
|
||||
projectId,
|
||||
{ $addToSet: { promptGroupIds: { $each: promptGroupIds } } },
|
||||
{ new: true },
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an array of prompt group IDs from a project's promptGroupIds array.
|
||||
*
|
||||
* @param {string} projectId - The ID of the project to update.
|
||||
* @param {string[]} promptGroupIds - The array of prompt group IDs to remove from the project.
|
||||
* @returns {Promise<IMongoProject>} The updated project document.
|
||||
*/
|
||||
const removeGroupIdsFromProject = async function (projectId, promptGroupIds) {
|
||||
return await Project.findByIdAndUpdate(
|
||||
projectId,
|
||||
{ $pullAll: { promptGroupIds: promptGroupIds } },
|
||||
{ new: true },
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a prompt group ID from all projects.
|
||||
*
|
||||
* @param {string} promptGroupId - The ID of the prompt group to remove from projects.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const removeGroupFromAllProjects = async (promptGroupId) => {
|
||||
await Project.updateMany({}, { $pullAll: { promptGroupIds: [promptGroupId] } });
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an array of agent IDs to a project's agentIds array, ensuring uniqueness.
|
||||
*
|
||||
* @param {string} projectId - The ID of the project to update.
|
||||
* @param {string[]} agentIds - The array of agent IDs to add to the project.
|
||||
* @returns {Promise<IMongoProject>} The updated project document.
|
||||
*/
|
||||
const addAgentIdsToProject = async function (projectId, agentIds) {
|
||||
return await Project.findByIdAndUpdate(
|
||||
projectId,
|
||||
{ $addToSet: { agentIds: { $each: agentIds } } },
|
||||
{ new: true },
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an array of agent IDs from a project's agentIds array.
|
||||
*
|
||||
* @param {string} projectId - The ID of the project to update.
|
||||
* @param {string[]} agentIds - The array of agent IDs to remove from the project.
|
||||
* @returns {Promise<IMongoProject>} The updated project document.
|
||||
*/
|
||||
const removeAgentIdsFromProject = async function (projectId, agentIds) {
|
||||
return await Project.findByIdAndUpdate(
|
||||
projectId,
|
||||
{ $pullAll: { agentIds: agentIds } },
|
||||
{ new: true },
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an agent ID from all projects.
|
||||
*
|
||||
* @param {string} agentId - The ID of the agent to remove from projects.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const removeAgentFromAllProjects = async (agentId) => {
|
||||
await Project.updateMany({}, { $pullAll: { agentIds: [agentId] } });
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getProjectById,
|
||||
getProjectByName,
|
||||
/* prompts */
|
||||
addGroupIdsToProject,
|
||||
removeGroupIdsFromProject,
|
||||
removeGroupFromAllProjects,
|
||||
/* agents */
|
||||
addAgentIdsToProject,
|
||||
removeAgentIdsFromProject,
|
||||
removeAgentFromAllProjects,
|
||||
};
|
||||
|
|
@ -1,18 +1,7 @@
|
|||
const { ObjectId } = require('mongodb');
|
||||
const { escapeRegExp } = require('@librechat/api');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const {
|
||||
Constants,
|
||||
SystemRoles,
|
||||
ResourceType,
|
||||
SystemCategories,
|
||||
} = require('librechat-data-provider');
|
||||
const {
|
||||
removeGroupFromAllProjects,
|
||||
removeGroupIdsFromProject,
|
||||
addGroupIdsToProject,
|
||||
getProjectByName,
|
||||
} = require('./Project');
|
||||
const { SystemRoles, ResourceType, SystemCategories } = require('librechat-data-provider');
|
||||
const { removeAllPermissions } = require('~/server/services/PermissionService');
|
||||
const { PromptGroup, Prompt, AclEntry } = require('~/db/models');
|
||||
|
||||
|
|
@ -48,34 +37,21 @@ const getAllPromptGroups = async (req, filter) => {
|
|||
try {
|
||||
const { name, ...query } = filter;
|
||||
|
||||
let searchShared = true;
|
||||
let searchSharedOnly = false;
|
||||
if (name) {
|
||||
query.name = new RegExp(escapeRegExp(name), 'i');
|
||||
}
|
||||
if (!query.category) {
|
||||
delete query.category;
|
||||
} else if (query.category === SystemCategories.MY_PROMPTS) {
|
||||
searchShared = false;
|
||||
delete query.category;
|
||||
} else if (query.category === SystemCategories.NO_CATEGORY) {
|
||||
query.category = '';
|
||||
} else if (query.category === SystemCategories.SHARED_PROMPTS) {
|
||||
searchSharedOnly = true;
|
||||
delete query.category;
|
||||
}
|
||||
|
||||
let combinedQuery = query;
|
||||
|
||||
if (searchShared) {
|
||||
const project = await getProjectByName(Constants.GLOBAL_PROJECT_NAME, 'promptGroupIds');
|
||||
if (project && project.promptGroupIds && project.promptGroupIds.length > 0) {
|
||||
const projectQuery = { _id: { $in: project.promptGroupIds }, ...query };
|
||||
delete projectQuery.author;
|
||||
combinedQuery = searchSharedOnly ? projectQuery : { $or: [projectQuery, query] };
|
||||
}
|
||||
}
|
||||
|
||||
const groups = await PromptGroup.find(combinedQuery)
|
||||
.sort({ createdAt: -1 })
|
||||
.select('name oneliner category author authorName createdAt updatedAt command productionId')
|
||||
|
|
@ -100,34 +76,21 @@ const getPromptGroups = async (req, filter) => {
|
|||
const validatedPageNumber = Math.max(parseInt(pageNumber, 10), 1);
|
||||
const validatedPageSize = Math.max(parseInt(pageSize, 10), 1);
|
||||
|
||||
let searchShared = true;
|
||||
let searchSharedOnly = false;
|
||||
if (name) {
|
||||
query.name = new RegExp(escapeRegExp(name), 'i');
|
||||
}
|
||||
if (!query.category) {
|
||||
delete query.category;
|
||||
} else if (query.category === SystemCategories.MY_PROMPTS) {
|
||||
searchShared = false;
|
||||
delete query.category;
|
||||
} else if (query.category === SystemCategories.NO_CATEGORY) {
|
||||
query.category = '';
|
||||
} else if (query.category === SystemCategories.SHARED_PROMPTS) {
|
||||
searchSharedOnly = true;
|
||||
delete query.category;
|
||||
}
|
||||
|
||||
let combinedQuery = query;
|
||||
|
||||
if (searchShared) {
|
||||
const project = await getProjectByName(Constants.GLOBAL_PROJECT_NAME, 'promptGroupIds');
|
||||
if (project && project.promptGroupIds && project.promptGroupIds.length > 0) {
|
||||
const projectQuery = { _id: { $in: project.promptGroupIds }, ...query };
|
||||
delete projectQuery.author;
|
||||
combinedQuery = searchSharedOnly ? projectQuery : { $or: [projectQuery, query] };
|
||||
}
|
||||
}
|
||||
|
||||
const skip = (validatedPageNumber - 1) * validatedPageSize;
|
||||
const limit = validatedPageSize;
|
||||
|
||||
|
|
@ -137,7 +100,7 @@ const getPromptGroups = async (req, filter) => {
|
|||
.skip(skip)
|
||||
.limit(limit)
|
||||
.select(
|
||||
'name numberOfGenerations oneliner category projectIds productionId author authorName createdAt updatedAt',
|
||||
'name numberOfGenerations oneliner category productionId author authorName createdAt updatedAt',
|
||||
)
|
||||
.lean(),
|
||||
PromptGroup.countDocuments(combinedQuery),
|
||||
|
|
@ -182,7 +145,6 @@ const deletePromptGroup = async ({ _id, author, role }) => {
|
|||
}
|
||||
|
||||
await Prompt.deleteMany(groupQuery);
|
||||
await removeGroupFromAllProjects(_id);
|
||||
|
||||
try {
|
||||
await removeAllPermissions({ resourceType: ResourceType.PROMPTGROUP, resourceId: _id });
|
||||
|
|
@ -241,7 +203,7 @@ async function getListPromptGroupsByAccess({
|
|||
const findQuery = PromptGroup.find(baseQuery)
|
||||
.sort({ updatedAt: -1, _id: 1 })
|
||||
.select(
|
||||
'name numberOfGenerations oneliner category projectIds productionId author authorName createdAt updatedAt',
|
||||
'name numberOfGenerations oneliner category productionId author authorName createdAt updatedAt',
|
||||
);
|
||||
|
||||
if (isPaginated) {
|
||||
|
|
@ -487,7 +449,6 @@ module.exports = {
|
|||
}
|
||||
|
||||
await PromptGroup.deleteOne({ _id: groupId });
|
||||
await removeGroupFromAllProjects(groupId);
|
||||
|
||||
return {
|
||||
prompt: 'Prompt deleted successfully',
|
||||
|
|
@ -523,10 +484,6 @@ module.exports = {
|
|||
|
||||
const groupIds = promptGroups.map((group) => group._id);
|
||||
|
||||
for (const groupId of groupIds) {
|
||||
await removeGroupFromAllProjects(groupId);
|
||||
}
|
||||
|
||||
await AclEntry.deleteMany({
|
||||
resourceType: ResourceType.PROMPTGROUP,
|
||||
resourceId: { $in: groupIds },
|
||||
|
|
@ -547,23 +504,6 @@ module.exports = {
|
|||
updatePromptGroup: async (filter, data) => {
|
||||
try {
|
||||
const updateOps = {};
|
||||
if (data.removeProjectIds) {
|
||||
for (const projectId of data.removeProjectIds) {
|
||||
await removeGroupIdsFromProject(projectId, [filter._id]);
|
||||
}
|
||||
|
||||
updateOps.$pullAll = { projectIds: data.removeProjectIds };
|
||||
delete data.removeProjectIds;
|
||||
}
|
||||
|
||||
if (data.projectIds) {
|
||||
for (const projectId of data.projectIds) {
|
||||
await addGroupIdsToProject(projectId, [filter._id]);
|
||||
}
|
||||
|
||||
updateOps.$addToSet = { projectIds: { $each: data.projectIds } };
|
||||
delete data.projectIds;
|
||||
}
|
||||
|
||||
const updateData = { ...data, ...updateOps };
|
||||
const updatedDoc = await PromptGroup.findOneAndUpdate(filter, updateData, {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const dbModels = require('~/db/models');
|
|||
logger.silent = true;
|
||||
|
||||
let mongoServer;
|
||||
let Prompt, PromptGroup, AclEntry, AccessRole, User, Group, Project;
|
||||
let Prompt, PromptGroup, AclEntry, AccessRole, User, Group;
|
||||
let promptFns, permissionService;
|
||||
let testUsers, testGroups, testRoles;
|
||||
|
||||
|
|
@ -36,7 +36,6 @@ beforeAll(async () => {
|
|||
AccessRole = dbModels.AccessRole;
|
||||
User = dbModels.User;
|
||||
Group = dbModels.Group;
|
||||
Project = dbModels.Project;
|
||||
|
||||
promptFns = require('~/models/Prompt');
|
||||
permissionService = require('~/server/services/PermissionService');
|
||||
|
|
@ -118,12 +117,6 @@ async function setupTestData() {
|
|||
description: 'Group with viewer access',
|
||||
}),
|
||||
};
|
||||
|
||||
await Project.create({
|
||||
name: 'Global',
|
||||
description: 'Global project',
|
||||
promptGroupIds: [],
|
||||
});
|
||||
}
|
||||
|
||||
describe('Prompt ACL Permissions', () => {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ const { ObjectId } = require('mongodb');
|
|||
const { logger } = require('@librechat/data-schemas');
|
||||
const { MongoMemoryServer } = require('mongodb-memory-server');
|
||||
const {
|
||||
Constants,
|
||||
ResourceType,
|
||||
AccessRoleIds,
|
||||
PrincipalType,
|
||||
|
|
@ -19,9 +18,9 @@ logger.silent = true;
|
|||
|
||||
describe('PromptGroup Migration Script', () => {
|
||||
let mongoServer;
|
||||
let Prompt, PromptGroup, AclEntry, AccessRole, User, Project;
|
||||
let Prompt, PromptGroup, AclEntry, AccessRole, User;
|
||||
let migrateToPromptGroupPermissions;
|
||||
let testOwner, testProject;
|
||||
let testOwner;
|
||||
let ownerRole, viewerRole;
|
||||
|
||||
beforeAll(async () => {
|
||||
|
|
@ -37,7 +36,6 @@ describe('PromptGroup Migration Script', () => {
|
|||
AclEntry = dbModels.AclEntry;
|
||||
AccessRole = dbModels.AccessRole;
|
||||
User = dbModels.User;
|
||||
Project = dbModels.Project;
|
||||
|
||||
// Create test user
|
||||
testOwner = await User.create({
|
||||
|
|
@ -46,11 +44,10 @@ describe('PromptGroup Migration Script', () => {
|
|||
role: 'USER',
|
||||
});
|
||||
|
||||
// Create test project with the proper name
|
||||
const projectName = Constants.GLOBAL_PROJECT_NAME || 'instance';
|
||||
testProject = await Project.create({
|
||||
// Create test project document in the raw `projects` collection
|
||||
const projectName = 'instance';
|
||||
await mongoose.connection.db.collection('projects').insertOne({
|
||||
name: projectName,
|
||||
description: 'Global project',
|
||||
promptGroupIds: [],
|
||||
});
|
||||
|
||||
|
|
@ -95,9 +92,9 @@ describe('PromptGroup Migration Script', () => {
|
|||
await Prompt.deleteMany({});
|
||||
await PromptGroup.deleteMany({});
|
||||
await AclEntry.deleteMany({});
|
||||
// Reset the project's promptGroupIds array
|
||||
testProject.promptGroupIds = [];
|
||||
await testProject.save();
|
||||
await mongoose.connection.db
|
||||
.collection('projects')
|
||||
.updateOne({ name: 'instance' }, { $set: { promptGroupIds: [] } });
|
||||
});
|
||||
|
||||
it('should categorize promptGroups correctly in dry run', async () => {
|
||||
|
|
@ -118,8 +115,9 @@ describe('PromptGroup Migration Script', () => {
|
|||
});
|
||||
|
||||
// Add global group to project's promptGroupIds array
|
||||
testProject.promptGroupIds = [globalPromptGroup._id];
|
||||
await testProject.save();
|
||||
await mongoose.connection.db
|
||||
.collection('projects')
|
||||
.updateOne({ name: 'instance' }, { $set: { promptGroupIds: [globalPromptGroup._id] } });
|
||||
|
||||
const result = await migrateToPromptGroupPermissions({ dryRun: true });
|
||||
|
||||
|
|
@ -146,8 +144,9 @@ describe('PromptGroup Migration Script', () => {
|
|||
});
|
||||
|
||||
// Add global group to project's promptGroupIds array
|
||||
testProject.promptGroupIds = [globalPromptGroup._id];
|
||||
await testProject.save();
|
||||
await mongoose.connection.db
|
||||
.collection('projects')
|
||||
.updateOne({ name: 'instance' }, { $set: { promptGroupIds: [globalPromptGroup._id] } });
|
||||
|
||||
const result = await migrateToPromptGroupPermissions({ dryRun: false });
|
||||
|
||||
|
|
|
|||
|
|
@ -173,9 +173,6 @@ const getAgentHandler = async (req, res, expandProperties = false) => {
|
|||
|
||||
agent.author = agent.author.toString();
|
||||
|
||||
// @deprecated - isCollaborative replaced by ACL permissions
|
||||
agent.isCollaborative = !!agent.isCollaborative;
|
||||
|
||||
// Check if agent is public
|
||||
const isPublic = await hasPublicPermission({
|
||||
resourceType: ResourceType.AGENT,
|
||||
|
|
@ -199,9 +196,6 @@ const getAgentHandler = async (req, res, expandProperties = false) => {
|
|||
author: agent.author,
|
||||
provider: agent.provider,
|
||||
model: agent.model,
|
||||
projectIds: agent.projectIds,
|
||||
// @deprecated - isCollaborative replaced by ACL permissions
|
||||
isCollaborative: agent.isCollaborative,
|
||||
isPublic: agent.isPublic,
|
||||
version: agent.version,
|
||||
// Safe metadata
|
||||
|
|
|
|||
|
|
@ -14,10 +14,6 @@ jest.mock('~/server/services/Config', () => ({
|
|||
}),
|
||||
}));
|
||||
|
||||
jest.mock('~/models/Project', () => ({
|
||||
getProjectByName: jest.fn().mockResolvedValue(null),
|
||||
}));
|
||||
|
||||
jest.mock('~/server/services/Files/strategies', () => ({
|
||||
getStrategyFunctions: jest.fn(),
|
||||
}));
|
||||
|
|
@ -174,7 +170,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
// Unauthorized fields that should be stripped
|
||||
author: new mongoose.Types.ObjectId().toString(), // Should not be able to set author
|
||||
authorName: 'Hacker', // Should be stripped
|
||||
isCollaborative: true, // Should be stripped on creation
|
||||
versions: [], // Should be stripped
|
||||
_id: new mongoose.Types.ObjectId(), // Should be stripped
|
||||
id: 'custom_agent_id', // Should be overridden
|
||||
|
|
@ -193,7 +188,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
// Verify unauthorized fields were not set
|
||||
expect(createdAgent.author.toString()).toBe(mockReq.user.id); // Should be the request user, not the malicious value
|
||||
expect(createdAgent.authorName).toBeUndefined();
|
||||
expect(createdAgent.isCollaborative).toBeFalsy();
|
||||
expect(createdAgent.versions).toHaveLength(1); // Should have exactly 1 version from creation
|
||||
expect(createdAgent.id).not.toBe('custom_agent_id'); // Should have generated ID
|
||||
expect(createdAgent.id).toMatch(/^agent_/); // Should have proper prefix
|
||||
|
|
@ -444,7 +438,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
model: 'gpt-3.5-turbo',
|
||||
author: existingAgentAuthorId,
|
||||
description: 'Original description',
|
||||
isCollaborative: false,
|
||||
versions: [
|
||||
{
|
||||
name: 'Original Agent',
|
||||
|
|
@ -466,7 +459,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
name: 'Updated Agent',
|
||||
description: 'Updated description',
|
||||
model: 'gpt-4',
|
||||
isCollaborative: true, // This IS allowed in updates
|
||||
};
|
||||
|
||||
await updateAgentHandler(mockReq, mockRes);
|
||||
|
|
@ -479,13 +471,11 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
expect(updatedAgent.name).toBe('Updated Agent');
|
||||
expect(updatedAgent.description).toBe('Updated description');
|
||||
expect(updatedAgent.model).toBe('gpt-4');
|
||||
expect(updatedAgent.isCollaborative).toBe(true);
|
||||
expect(updatedAgent.author).toBe(existingAgentAuthorId.toString());
|
||||
|
||||
// Verify in database
|
||||
const agentInDb = await Agent.findOne({ id: existingAgentId });
|
||||
expect(agentInDb.name).toBe('Updated Agent');
|
||||
expect(agentInDb.isCollaborative).toBe(true);
|
||||
});
|
||||
|
||||
test('should reject update with unauthorized fields (mass assignment protection)', async () => {
|
||||
|
|
@ -540,25 +530,6 @@ describe('Agent Controllers - Mass Assignment Protection', () => {
|
|||
expect(updatedAgent.name).toBe('Admin Update');
|
||||
});
|
||||
|
||||
test('should handle projectIds updates', async () => {
|
||||
mockReq.user.id = existingAgentAuthorId.toString();
|
||||
mockReq.params.id = existingAgentId;
|
||||
|
||||
const projectId1 = new mongoose.Types.ObjectId().toString();
|
||||
const projectId2 = new mongoose.Types.ObjectId().toString();
|
||||
|
||||
mockReq.body = {
|
||||
projectIds: [projectId1, projectId2],
|
||||
};
|
||||
|
||||
await updateAgentHandler(mockReq, mockRes);
|
||||
|
||||
expect(mockRes.json).toHaveBeenCalled();
|
||||
|
||||
const updatedAgent = mockRes.json.mock.calls[0][0];
|
||||
expect(updatedAgent).toBeDefined();
|
||||
});
|
||||
|
||||
test('should validate tool_resources in updates', async () => {
|
||||
mockReq.user.id = existingAgentAuthorId.toString();
|
||||
mockReq.params.id = existingAgentId;
|
||||
|
|
|
|||
|
|
@ -21,15 +21,6 @@ const checkAgentCreate = generateCheckAccess({
|
|||
getRoleByName,
|
||||
});
|
||||
|
||||
const checkGlobalAgentShare = generateCheckAccess({
|
||||
permissionType: PermissionTypes.AGENTS,
|
||||
permissions: [Permissions.USE, Permissions.CREATE],
|
||||
bodyProps: {
|
||||
[Permissions.SHARE]: ['projectIds', 'removeProjectIds'],
|
||||
},
|
||||
getRoleByName,
|
||||
});
|
||||
|
||||
router.use(requireJwtAuth);
|
||||
|
||||
/**
|
||||
|
|
@ -99,7 +90,7 @@ router.get(
|
|||
*/
|
||||
router.patch(
|
||||
'/:id',
|
||||
checkGlobalAgentShare,
|
||||
checkAgentCreate,
|
||||
canAccessAgentResource({
|
||||
requiredPermission: PermissionBits.EDIT,
|
||||
resourceIdParam: 'id',
|
||||
|
|
@ -148,7 +139,7 @@ router.delete(
|
|||
*/
|
||||
router.post(
|
||||
'/:id/revert',
|
||||
checkGlobalAgentShare,
|
||||
checkAgentCreate,
|
||||
canAccessAgentResource({
|
||||
requiredPermission: PermissionBits.EDIT,
|
||||
resourceIdParam: 'id',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
const express = require('express');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { isEnabled, getBalanceConfig } = require('@librechat/api');
|
||||
const { Constants, CacheKeys, defaultSocialLogins } = require('librechat-data-provider');
|
||||
const { CacheKeys, defaultSocialLogins } = require('librechat-data-provider');
|
||||
const { getLdapConfig } = require('~/server/services/Config/ldap');
|
||||
const { getAppConfig } = require('~/server/services/Config/app');
|
||||
const { getProjectByName } = require('~/models/Project');
|
||||
const { getLogStores } = require('~/cache');
|
||||
|
||||
const router = express.Router();
|
||||
|
|
@ -37,8 +36,6 @@ router.get('/', async function (req, res) {
|
|||
return today.getMonth() === 1 && today.getDate() === 11;
|
||||
};
|
||||
|
||||
const instanceProject = await getProjectByName(Constants.GLOBAL_PROJECT_NAME, '_id');
|
||||
|
||||
const ldap = getLdapConfig();
|
||||
|
||||
try {
|
||||
|
|
@ -101,7 +98,6 @@ router.get('/', async function (req, res) {
|
|||
sharedLinksEnabled,
|
||||
publicSharedLinksEnabled,
|
||||
analyticsGtmId: process.env.ANALYTICS_GTM_ID,
|
||||
instanceProjectId: instanceProject._id.toString(),
|
||||
bundlerURL: process.env.SANDPACK_BUNDLER_URL,
|
||||
staticBundlerURL: process.env.SANDPACK_STATIC_BUNDLER_URL,
|
||||
sharePointFilePickerEnabled,
|
||||
|
|
|
|||
|
|
@ -56,15 +56,6 @@ const checkPromptCreate = generateCheckAccess({
|
|||
getRoleByName,
|
||||
});
|
||||
|
||||
const checkGlobalPromptShare = generateCheckAccess({
|
||||
permissionType: PermissionTypes.PROMPTS,
|
||||
permissions: [Permissions.USE, Permissions.CREATE],
|
||||
bodyProps: {
|
||||
[Permissions.SHARE]: ['projectIds', 'removeProjectIds'],
|
||||
},
|
||||
getRoleByName,
|
||||
});
|
||||
|
||||
router.use(requireJwtAuth);
|
||||
router.use(checkPromptAccess);
|
||||
|
||||
|
|
@ -364,7 +355,7 @@ const patchPromptGroup = async (req, res) => {
|
|||
|
||||
router.patch(
|
||||
'/groups/:groupId',
|
||||
checkGlobalPromptShare,
|
||||
checkPromptCreate,
|
||||
canAccessPromptGroupResource({
|
||||
requiredPermission: PermissionBits.EDIT,
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ const {
|
|||
checkAgentPermissionsMigration,
|
||||
checkPromptPermissionsMigration,
|
||||
} = require('@librechat/api');
|
||||
const { getProjectByName } = require('~/models/Project');
|
||||
const { Agent, PromptGroup } = require('~/db/models');
|
||||
const { findRoleByIdentifier } = require('~/models');
|
||||
|
||||
|
|
@ -20,7 +19,6 @@ async function checkMigrations() {
|
|||
mongoose,
|
||||
methods: {
|
||||
findRoleByIdentifier,
|
||||
getProjectByName,
|
||||
},
|
||||
AgentModel: Agent,
|
||||
});
|
||||
|
|
@ -33,7 +31,6 @@ async function checkMigrations() {
|
|||
mongoose,
|
||||
methods: {
|
||||
findRoleByIdentifier,
|
||||
getProjectByName,
|
||||
},
|
||||
PromptGroupModel: PromptGroup,
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue