mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-22 06:00:56 +02:00
🗞️ refactor: Apply Role Permissions at Startup only if Missing or Configured
This commit is contained in:
parent
d07c2b3475
commit
53c31b85d0
7 changed files with 355 additions and 440 deletions
|
@ -16,7 +16,7 @@ const { Role } = require('~/db/models');
|
||||||
*
|
*
|
||||||
* @param {string} roleName - The name of the role to find or create.
|
* @param {string} roleName - The name of the role to find or create.
|
||||||
* @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
|
* @param {string|string[]} [fieldsToSelect] - The fields to include or exclude in the returned document.
|
||||||
* @returns {Promise<Object>} A plain object representing the role document.
|
* @returns {Promise<IRole>} Role document.
|
||||||
*/
|
*/
|
||||||
const getRoleByName = async function (roleName, fieldsToSelect = null) {
|
const getRoleByName = async function (roleName, fieldsToSelect = null) {
|
||||||
const cache = getLogStores(CacheKeys.ROLES);
|
const cache = getLogStores(CacheKeys.ROLES);
|
||||||
|
@ -72,8 +72,9 @@ const updateRoleByName = async function (roleName, updates) {
|
||||||
* Updates access permissions for a specific role and multiple permission types.
|
* Updates access permissions for a specific role and multiple permission types.
|
||||||
* @param {string} roleName - The role to update.
|
* @param {string} roleName - The role to update.
|
||||||
* @param {Object.<PermissionTypes, Object.<Permissions, boolean>>} permissionsUpdate - Permissions to update and their values.
|
* @param {Object.<PermissionTypes, Object.<Permissions, boolean>>} permissionsUpdate - Permissions to update and their values.
|
||||||
|
* @param {IRole} [roleData] - Optional role data to use instead of fetching from the database.
|
||||||
*/
|
*/
|
||||||
async function updateAccessPermissions(roleName, permissionsUpdate) {
|
async function updateAccessPermissions(roleName, permissionsUpdate, roleData) {
|
||||||
// Filter and clean the permission updates based on our schema definition.
|
// Filter and clean the permission updates based on our schema definition.
|
||||||
const updates = {};
|
const updates = {};
|
||||||
for (const [permissionType, permissions] of Object.entries(permissionsUpdate)) {
|
for (const [permissionType, permissions] of Object.entries(permissionsUpdate)) {
|
||||||
|
@ -86,7 +87,7 @@ async function updateAccessPermissions(roleName, permissionsUpdate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const role = await getRoleByName(roleName);
|
const role = roleData ?? (await getRoleByName(roleName));
|
||||||
if (!role) {
|
if (!role) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +114,6 @@ async function updateAccessPermissions(roleName, permissionsUpdate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the current updates
|
|
||||||
for (const [permissionType, permissions] of Object.entries(updates)) {
|
for (const [permissionType, permissions] of Object.entries(updates)) {
|
||||||
const currentTypePermissions = currentPermissions[permissionType] || {};
|
const currentTypePermissions = currentPermissions[permissionType] || {};
|
||||||
updatedPermissions[permissionType] = { ...currentTypePermissions };
|
updatedPermissions[permissionType] = { ...currentTypePermissions };
|
||||||
|
|
|
@ -5,7 +5,7 @@ jest.mock('~/models', () => ({
|
||||||
}));
|
}));
|
||||||
jest.mock('~/models/Role', () => ({
|
jest.mock('~/models/Role', () => ({
|
||||||
updateAccessPermissions: jest.fn(),
|
updateAccessPermissions: jest.fn(),
|
||||||
getRoleByName: jest.fn(),
|
getRoleByName: jest.fn().mockResolvedValue(null),
|
||||||
updateRoleByName: jest.fn(),
|
updateRoleByName: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ jest.mock('~/models', () => ({
|
||||||
}));
|
}));
|
||||||
jest.mock('~/models/Role', () => ({
|
jest.mock('~/models/Role', () => ({
|
||||||
updateAccessPermissions: jest.fn(),
|
updateAccessPermissions: jest.fn(),
|
||||||
|
getRoleByName: jest.fn().mockResolvedValue(null),
|
||||||
}));
|
}));
|
||||||
jest.mock('./Config', () => ({
|
jest.mock('./Config', () => ({
|
||||||
setCachedTools: jest.fn(),
|
setCachedTools: jest.fn(),
|
||||||
|
|
|
@ -6,16 +6,86 @@ const {
|
||||||
} = require('librechat-data-provider');
|
} = require('librechat-data-provider');
|
||||||
const { logger } = require('@librechat/data-schemas');
|
const { logger } = require('@librechat/data-schemas');
|
||||||
const { isMemoryEnabled } = require('@librechat/api');
|
const { isMemoryEnabled } = require('@librechat/api');
|
||||||
const { updateAccessPermissions } = require('~/models/Role');
|
const { updateAccessPermissions, getRoleByName } = require('~/models/Role');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates role permissions intelligently - only updates permission types that:
|
||||||
|
* 1. Don't exist in the database (first time setup)
|
||||||
|
* 2. Are explicitly configured in the config file
|
||||||
|
* @param {object} params - The role name to update
|
||||||
|
* @param {string} params.roleName - The role name to update
|
||||||
|
* @param {object} params.allPermissions - All permissions to potentially update
|
||||||
|
* @param {object} params.interfaceConfig - The interface config from librechat.yaml
|
||||||
|
*/
|
||||||
|
async function updateRolePermissions({ roleName, allPermissions, interfaceConfig }) {
|
||||||
|
const existingRole = await getRoleByName(roleName);
|
||||||
|
const existingPermissions = existingRole?.permissions || {};
|
||||||
|
const permissionsToUpdate = {};
|
||||||
|
|
||||||
|
for (const [permType, perms] of Object.entries(allPermissions)) {
|
||||||
|
const permTypeExists = existingPermissions[permType];
|
||||||
|
|
||||||
|
const isExplicitlyConfigured = interfaceConfig && hasExplicitConfig(interfaceConfig, permType);
|
||||||
|
|
||||||
|
// Only update if: doesn't exist OR explicitly configured
|
||||||
|
if (!permTypeExists || isExplicitlyConfigured) {
|
||||||
|
permissionsToUpdate[permType] = perms;
|
||||||
|
if (!permTypeExists) {
|
||||||
|
logger.debug(`Role '${roleName}': Setting up default permissions for '${permType}'`);
|
||||||
|
} else if (isExplicitlyConfigured) {
|
||||||
|
logger.debug(`Role '${roleName}': Applying explicit config for '${permType}'`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.debug(`Role '${roleName}': Preserving existing permissions for '${permType}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(permissionsToUpdate).length > 0) {
|
||||||
|
await updateAccessPermissions(roleName, permissionsToUpdate, existingRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a permission type has explicit configuration
|
||||||
|
*/
|
||||||
|
function hasExplicitConfig(interfaceConfig, permissionType) {
|
||||||
|
switch (permissionType) {
|
||||||
|
case PermissionTypes.PROMPTS:
|
||||||
|
return interfaceConfig.prompts !== undefined;
|
||||||
|
case PermissionTypes.BOOKMARKS:
|
||||||
|
return interfaceConfig.bookmarks !== undefined;
|
||||||
|
case PermissionTypes.MEMORIES:
|
||||||
|
return interfaceConfig.memories !== undefined;
|
||||||
|
case PermissionTypes.MULTI_CONVO:
|
||||||
|
return interfaceConfig.multiConvo !== undefined;
|
||||||
|
case PermissionTypes.AGENTS:
|
||||||
|
return interfaceConfig.agents !== undefined;
|
||||||
|
case PermissionTypes.TEMPORARY_CHAT:
|
||||||
|
return interfaceConfig.temporaryChat !== undefined;
|
||||||
|
case PermissionTypes.RUN_CODE:
|
||||||
|
return interfaceConfig.runCode !== undefined;
|
||||||
|
case PermissionTypes.WEB_SEARCH:
|
||||||
|
return interfaceConfig.webSearch !== undefined;
|
||||||
|
case PermissionTypes.PEOPLE_PICKER:
|
||||||
|
return interfaceConfig.peoplePicker !== undefined;
|
||||||
|
case PermissionTypes.MARKETPLACE:
|
||||||
|
return interfaceConfig.marketplace !== undefined;
|
||||||
|
case PermissionTypes.FILE_SEARCH:
|
||||||
|
return interfaceConfig.fileSearch !== undefined;
|
||||||
|
case PermissionTypes.FILE_CITATIONS:
|
||||||
|
return interfaceConfig.fileCitations !== undefined;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the default interface object.
|
* Loads the default interface object.
|
||||||
* @param {TCustomConfig | undefined} config - The loaded custom configuration.
|
* @param {TCustomConfig | undefined} config - The loaded custom configuration.
|
||||||
* @param {TConfigDefaults} configDefaults - The custom configuration default values.
|
* @param {TConfigDefaults} configDefaults - The custom configuration default values.
|
||||||
* @param {SystemRoles} [roleName] - The role to load the default interface for, defaults to `'USER'`.
|
|
||||||
* @returns {Promise<TCustomConfig['interface']>} The default interface object.
|
* @returns {Promise<TCustomConfig['interface']>} The default interface object.
|
||||||
*/
|
*/
|
||||||
async function loadDefaultInterface(config, configDefaults, roleName = SystemRoles.USER) {
|
async function loadDefaultInterface(config, configDefaults) {
|
||||||
const { interface: interfaceConfig } = config ?? {};
|
const { interface: interfaceConfig } = config ?? {};
|
||||||
const { interface: defaults } = configDefaults;
|
const { interface: defaults } = configDefaults;
|
||||||
const hasModelSpecs = config?.modelSpecs?.list?.length > 0;
|
const hasModelSpecs = config?.modelSpecs?.list?.length > 0;
|
||||||
|
@ -63,33 +133,10 @@ async function loadDefaultInterface(config, configDefaults, roleName = SystemRol
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await updateAccessPermissions(roleName, {
|
for (const roleName of [SystemRoles.USER, SystemRoles.ADMIN]) {
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: loadedInterface.prompts },
|
await updateRolePermissions({
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks },
|
roleName,
|
||||||
[PermissionTypes.MEMORIES]: {
|
allPermissions: {
|
||||||
[Permissions.USE]: loadedInterface.memories,
|
|
||||||
[Permissions.OPT_OUT]: isPersonalizationEnabled,
|
|
||||||
},
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: loadedInterface.multiConvo },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: loadedInterface.agents },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: loadedInterface.temporaryChat },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: loadedInterface.runCode },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: loadedInterface.webSearch },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_USERS]:
|
|
||||||
roleName === SystemRoles.USER ? false : loadedInterface.peoplePicker?.users,
|
|
||||||
[Permissions.VIEW_GROUPS]:
|
|
||||||
roleName === SystemRoles.USER ? false : loadedInterface.peoplePicker?.groups,
|
|
||||||
[Permissions.VIEW_ROLES]:
|
|
||||||
roleName === SystemRoles.USER ? false : loadedInterface.peoplePicker?.roles,
|
|
||||||
},
|
|
||||||
[PermissionTypes.MARKETPLACE]: {
|
|
||||||
[Permissions.USE]: roleName === SystemRoles.USER ? false : loadedInterface.marketplace?.use,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: loadedInterface.fileSearch },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: loadedInterface.fileCitations },
|
|
||||||
});
|
|
||||||
await updateAccessPermissions(SystemRoles.ADMIN, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: loadedInterface.prompts },
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: loadedInterface.prompts },
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks },
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks },
|
||||||
[PermissionTypes.MEMORIES]: {
|
[PermissionTypes.MEMORIES]: {
|
||||||
|
@ -111,7 +158,10 @@ async function loadDefaultInterface(config, configDefaults, roleName = SystemRol
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: loadedInterface.fileSearch },
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: loadedInterface.fileSearch },
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: loadedInterface.fileCitations },
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: loadedInterface.fileCitations },
|
||||||
|
},
|
||||||
|
interfaceConfig,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const logSettings = () => {
|
const logSettings = () => {
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
const { SystemRoles, Permissions, PermissionTypes } = require('librechat-data-provider');
|
const { SystemRoles, Permissions, PermissionTypes } = require('librechat-data-provider');
|
||||||
const { updateAccessPermissions } = require('~/models/Role');
|
const { updateAccessPermissions, getRoleByName } = require('~/models/Role');
|
||||||
const { loadDefaultInterface } = require('./interface');
|
const { loadDefaultInterface } = require('./interface');
|
||||||
|
|
||||||
jest.mock('~/models/Role', () => ({
|
jest.mock('~/models/Role', () => ({
|
||||||
updateAccessPermissions: jest.fn(),
|
updateAccessPermissions: jest.fn(),
|
||||||
|
getRoleByName: jest.fn(),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('loadDefaultInterface', () => {
|
describe('loadDefaultInterface', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
// Mock getRoleByName to return null (no existing permissions)
|
||||||
|
getRoleByName.mockResolvedValue(null);
|
||||||
|
});
|
||||||
|
|
||||||
it('should call updateAccessPermissions with the correct parameters when permission types are true', async () => {
|
it('should call updateAccessPermissions with the correct parameters when permission types are true', async () => {
|
||||||
const config = {
|
const config = {
|
||||||
interface: {
|
interface: {
|
||||||
|
@ -20,13 +27,21 @@ describe('loadDefaultInterface', () => {
|
||||||
webSearch: true,
|
webSearch: true,
|
||||||
fileSearch: true,
|
fileSearch: true,
|
||||||
fileCitations: true,
|
fileCitations: true,
|
||||||
|
peoplePicker: {
|
||||||
|
users: true,
|
||||||
|
groups: true,
|
||||||
|
roles: true,
|
||||||
|
},
|
||||||
|
marketplace: {
|
||||||
|
use: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const configDefaults = { interface: {} };
|
const configDefaults = { interface: {} };
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
await loadDefaultInterface(config, configDefaults);
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
const expectedPermissions = {
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.MEMORIES]: {
|
[PermissionTypes.MEMORIES]: {
|
||||||
|
@ -38,14 +53,31 @@ describe('loadDefaultInterface', () => {
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: true },
|
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
[PermissionTypes.PEOPLE_PICKER]: {
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
[Permissions.VIEW_USERS]: true,
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[Permissions.VIEW_GROUPS]: true,
|
||||||
|
[Permissions.VIEW_ROLES]: true,
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
||||||
});
|
};
|
||||||
|
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
// Check USER role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.USER,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check ADMIN role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.ADMIN,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call updateAccessPermissions with false when permission types are false', async () => {
|
it('should call updateAccessPermissions with false when permission types are false', async () => {
|
||||||
|
@ -61,13 +93,21 @@ describe('loadDefaultInterface', () => {
|
||||||
webSearch: false,
|
webSearch: false,
|
||||||
fileSearch: false,
|
fileSearch: false,
|
||||||
fileCitations: false,
|
fileCitations: false,
|
||||||
|
peoplePicker: {
|
||||||
|
users: false,
|
||||||
|
groups: false,
|
||||||
|
roles: false,
|
||||||
|
},
|
||||||
|
marketplace: {
|
||||||
|
use: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const configDefaults = { interface: {} };
|
const configDefaults = { interface: {} };
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
await loadDefaultInterface(config, configDefaults);
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
const expectedPermissions = {
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.MEMORIES]: { [Permissions.USE]: false, [Permissions.OPT_OUT]: undefined },
|
[PermissionTypes.MEMORIES]: { [Permissions.USE]: false, [Permissions.OPT_OUT]: undefined },
|
||||||
|
@ -76,14 +116,31 @@ describe('loadDefaultInterface', () => {
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: false },
|
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: false },
|
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: false },
|
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
[PermissionTypes.PEOPLE_PICKER]: {
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
[Permissions.VIEW_USERS]: false,
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[Permissions.VIEW_GROUPS]: false,
|
||||||
|
[Permissions.VIEW_ROLES]: false,
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: false },
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: false },
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: false },
|
||||||
});
|
};
|
||||||
|
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
// Check USER role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.USER,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check ADMIN role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.ADMIN,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call updateAccessPermissions with undefined when permission types are not specified in config', async () => {
|
it('should call updateAccessPermissions with undefined when permission types are not specified in config', async () => {
|
||||||
|
@ -92,7 +149,7 @@ describe('loadDefaultInterface', () => {
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
await loadDefaultInterface(config, configDefaults);
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
const expectedPermissions = {
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.MEMORIES]: {
|
[PermissionTypes.MEMORIES]: {
|
||||||
|
@ -106,52 +163,29 @@ describe('loadDefaultInterface', () => {
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
[PermissionTypes.PEOPLE_PICKER]: {
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[Permissions.VIEW_USERS]: undefined,
|
||||||
|
[Permissions.VIEW_GROUPS]: undefined,
|
||||||
|
[Permissions.VIEW_ROLES]: undefined,
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with undefined when permission types are explicitly undefined', async () => {
|
|
||||||
const config = {
|
|
||||||
interface: {
|
|
||||||
prompts: undefined,
|
|
||||||
bookmarks: undefined,
|
|
||||||
memories: undefined,
|
|
||||||
multiConvo: undefined,
|
|
||||||
agents: undefined,
|
|
||||||
temporaryChat: undefined,
|
|
||||||
runCode: undefined,
|
|
||||||
webSearch: undefined,
|
|
||||||
fileSearch: undefined,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
// Check USER role call
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
SystemRoles.USER,
|
||||||
[PermissionTypes.MEMORIES]: {
|
expectedPermissions,
|
||||||
[Permissions.USE]: undefined,
|
null,
|
||||||
[Permissions.OPT_OUT]: undefined,
|
);
|
||||||
},
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined },
|
// Check ADMIN role call
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
SystemRoles.ADMIN,
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
expectedPermissions,
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
null,
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
);
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call updateAccessPermissions with mixed values for permission types', async () => {
|
it('should call updateAccessPermissions with mixed values for permission types', async () => {
|
||||||
|
@ -173,7 +207,7 @@ describe('loadDefaultInterface', () => {
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
await loadDefaultInterface(config, configDefaults);
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
const expectedPermissions = {
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
||||||
|
@ -184,15 +218,103 @@ describe('loadDefaultInterface', () => {
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
[PermissionTypes.PEOPLE_PICKER]: {
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[Permissions.VIEW_USERS]: undefined,
|
||||||
|
[Permissions.VIEW_GROUPS]: undefined,
|
||||||
|
[Permissions.VIEW_ROLES]: undefined,
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: false },
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
||||||
});
|
};
|
||||||
|
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
// Check USER role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.USER,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check ADMIN role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.ADMIN,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should use default values when config is undefined', async () => {
|
||||||
|
const config = undefined;
|
||||||
|
const configDefaults = {
|
||||||
|
interface: {
|
||||||
|
prompts: true,
|
||||||
|
bookmarks: true,
|
||||||
|
memories: true,
|
||||||
|
multiConvo: true,
|
||||||
|
agents: true,
|
||||||
|
temporaryChat: true,
|
||||||
|
runCode: true,
|
||||||
|
webSearch: true,
|
||||||
|
fileSearch: true,
|
||||||
|
fileCitations: true,
|
||||||
|
peoplePicker: {
|
||||||
|
users: true,
|
||||||
|
groups: true,
|
||||||
|
roles: true,
|
||||||
|
},
|
||||||
|
marketplace: {
|
||||||
|
use: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await loadDefaultInterface(config, configDefaults);
|
||||||
|
|
||||||
|
const expectedPermissions = {
|
||||||
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
||||||
|
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: false },
|
||||||
|
[PermissionTypes.PEOPLE_PICKER]: {
|
||||||
|
[Permissions.VIEW_USERS]: true,
|
||||||
|
[Permissions.VIEW_GROUPS]: true,
|
||||||
|
[Permissions.VIEW_ROLES]: true,
|
||||||
|
},
|
||||||
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
|
// Check USER role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.USER,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check ADMIN role call
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
|
SystemRoles.ADMIN,
|
||||||
|
expectedPermissions,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only update permissions that do not exist when no config provided', async () => {
|
||||||
|
// Mock that some permissions already exist
|
||||||
|
getRoleByName.mockResolvedValue({
|
||||||
|
permissions: {
|
||||||
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
|
||||||
|
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call updateAccessPermissions with true when config is undefined', async () => {
|
|
||||||
const config = undefined;
|
const config = undefined;
|
||||||
const configDefaults = {
|
const configDefaults = {
|
||||||
interface: {
|
interface: {
|
||||||
|
@ -211,372 +333,110 @@ describe('loadDefaultInterface', () => {
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
await loadDefaultInterface(config, configDefaults);
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
// Should be called with all permissions EXCEPT prompts and agents (which already exist)
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
const expectedPermissions = {
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
|
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: true },
|
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
[PermissionTypes.PEOPLE_PICKER]: {
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[Permissions.VIEW_USERS]: undefined,
|
||||||
|
[Permissions.VIEW_GROUPS]: undefined,
|
||||||
|
[Permissions.VIEW_ROLES]: undefined,
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
||||||
});
|
};
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with the correct parameters when multiConvo is true', async () => {
|
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
|
||||||
const config = { interface: { multiConvo: true } };
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
const configDefaults = { interface: {} };
|
SystemRoles.USER,
|
||||||
|
expectedPermissions,
|
||||||
await loadDefaultInterface(config, configDefaults);
|
expect.objectContaining({
|
||||||
|
permissions: {
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MEMORIES]: {
|
|
||||||
[Permissions.USE]: undefined,
|
|
||||||
[Permissions.OPT_OUT]: undefined,
|
|
||||||
},
|
},
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
|
}),
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
);
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
SystemRoles.ADMIN,
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
expectedPermissions,
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
expect.objectContaining({
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
permissions: {
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
}),
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
);
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call updateAccessPermissions with false when multiConvo is false', async () => {
|
it('should override existing permissions when explicitly configured', async () => {
|
||||||
const config = { interface: { multiConvo: false } };
|
// Mock that some permissions already exist
|
||||||
const configDefaults = { interface: {} };
|
getRoleByName.mockResolvedValue({
|
||||||
|
permissions: {
|
||||||
await loadDefaultInterface(config, configDefaults);
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
|
||||||
|
[PermissionTypes.AGENTS]: { [Permissions.USE]: false },
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MEMORIES]: {
|
|
||||||
[Permissions.USE]: undefined,
|
|
||||||
[Permissions.OPT_OUT]: undefined,
|
|
||||||
},
|
},
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call updateAccessPermissions with undefined when multiConvo is not specified in config', async () => {
|
|
||||||
const config = {};
|
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MEMORIES]: {
|
|
||||||
[Permissions.USE]: undefined,
|
|
||||||
[Permissions.OPT_OUT]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with all interface options including multiConvo', async () => {
|
|
||||||
const config = {
|
const config = {
|
||||||
interface: {
|
interface: {
|
||||||
prompts: true,
|
prompts: true, // Explicitly set, should override existing false
|
||||||
bookmarks: false,
|
// agents not specified, so existing false should be preserved
|
||||||
memories: true,
|
// bookmarks not specified, so existing false should be preserved
|
||||||
multiConvo: true,
|
|
||||||
agents: false,
|
|
||||||
temporaryChat: true,
|
|
||||||
runCode: false,
|
|
||||||
fileSearch: true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should use default values for multiConvo when config is undefined', async () => {
|
|
||||||
const config = undefined;
|
|
||||||
const configDefaults = {
|
const configDefaults = {
|
||||||
interface: {
|
interface: {
|
||||||
prompts: true,
|
prompts: false,
|
||||||
|
agents: true,
|
||||||
bookmarks: true,
|
bookmarks: true,
|
||||||
memories: false,
|
|
||||||
multiConvo: false,
|
|
||||||
agents: undefined,
|
|
||||||
temporaryChat: undefined,
|
|
||||||
runCode: undefined,
|
|
||||||
webSearch: undefined,
|
|
||||||
fileSearch: true,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
await loadDefaultInterface(config, configDefaults);
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
// Should update prompts (explicitly configured) and all other permissions that don't exist
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
const expectedPermissions = {
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true }, // Explicitly configured
|
||||||
[PermissionTypes.MEMORIES]: { [Permissions.USE]: false, [Permissions.OPT_OUT]: undefined },
|
// All other permissions that don't exist in the database
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: false },
|
[PermissionTypes.MEMORIES]: {
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
[Permissions.USE]: undefined,
|
||||||
|
[Permissions.OPT_OUT]: undefined,
|
||||||
|
},
|
||||||
|
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
[PermissionTypes.PEOPLE_PICKER]: {
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[Permissions.VIEW_USERS]: undefined,
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with the correct parameters when WEB_SEARCH is undefined', async () => {
|
|
||||||
const config = {
|
|
||||||
interface: {
|
|
||||||
prompts: true,
|
|
||||||
bookmarks: false,
|
|
||||||
memories: true,
|
|
||||||
multiConvo: true,
|
|
||||||
agents: false,
|
|
||||||
temporaryChat: true,
|
|
||||||
runCode: false,
|
|
||||||
fileCitations: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
[Permissions.VIEW_GROUPS]: undefined,
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
[Permissions.VIEW_ROLES]: undefined,
|
||||||
},
|
},
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with the correct parameters when FILE_SEARCH is true', async () => {
|
|
||||||
const config = {
|
|
||||||
interface: {
|
|
||||||
fileSearch: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MEMORIES]: {
|
|
||||||
[Permissions.USE]: undefined,
|
|
||||||
[Permissions.OPT_OUT]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with false when FILE_SEARCH is false', async () => {
|
|
||||||
const config = {
|
|
||||||
interface: {
|
|
||||||
fileSearch: false,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
|
||||||
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
SystemRoles.USER,
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
expectedPermissions,
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
expect.objectContaining({
|
||||||
[PermissionTypes.MEMORIES]: {
|
permissions: expect.any(Object),
|
||||||
[Permissions.USE]: undefined,
|
}),
|
||||||
[Permissions.OPT_OUT]: undefined,
|
);
|
||||||
},
|
expect(updateAccessPermissions).toHaveBeenCalledWith(
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined },
|
SystemRoles.ADMIN,
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
expectedPermissions,
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
expect.objectContaining({
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
permissions: expect.any(Object),
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
}),
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
);
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with all interface options including fileSearch', async () => {
|
|
||||||
const config = {
|
|
||||||
interface: {
|
|
||||||
prompts: true,
|
|
||||||
bookmarks: false,
|
|
||||||
memories: true,
|
|
||||||
multiConvo: true,
|
|
||||||
agents: false,
|
|
||||||
temporaryChat: true,
|
|
||||||
runCode: false,
|
|
||||||
webSearch: true,
|
|
||||||
fileSearch: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.MEMORIES]: { [Permissions.USE]: true, [Permissions.OPT_OUT]: undefined },
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with the correct parameters when fileCitations is true', async () => {
|
|
||||||
const config = { interface: { fileCitations: true } };
|
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MEMORIES]: {
|
|
||||||
[Permissions.USE]: undefined,
|
|
||||||
[Permissions.OPT_OUT]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: true },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should call updateAccessPermissions with false when fileCitations is false', async () => {
|
|
||||||
const config = { interface: { fileCitations: false } };
|
|
||||||
const configDefaults = { interface: {} };
|
|
||||||
|
|
||||||
await loadDefaultInterface(config, configDefaults);
|
|
||||||
|
|
||||||
expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, {
|
|
||||||
[PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.MEMORIES]: {
|
|
||||||
[Permissions.USE]: undefined,
|
|
||||||
[Permissions.OPT_OUT]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.AGENTS]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: false },
|
|
||||||
[PermissionTypes.MARKETPLACE]: { [Permissions.USE]: undefined },
|
|
||||||
[PermissionTypes.PEOPLE_PICKER]: {
|
|
||||||
[Permissions.VIEW_GROUPS]: undefined,
|
|
||||||
[Permissions.VIEW_USERS]: undefined,
|
|
||||||
},
|
|
||||||
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: undefined },
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -888,6 +888,12 @@
|
||||||
* @memberof typedefs
|
* @memberof typedefs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @exports IRole
|
||||||
|
* @typedef {import('@librechat/data-schemas').IRole} IRole
|
||||||
|
* @memberof typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @exports ObjectId
|
* @exports ObjectId
|
||||||
* @typedef {import('mongoose').Types.ObjectId} ObjectId
|
* @typedef {import('mongoose').Types.ObjectId} ObjectId
|
||||||
|
|
|
@ -594,8 +594,6 @@
|
||||||
"com_ui_people_picker_allow_view_roles": "Allow viewing roles",
|
"com_ui_people_picker_allow_view_roles": "Allow viewing roles",
|
||||||
"com_ui_marketplace": "Marketplace",
|
"com_ui_marketplace": "Marketplace",
|
||||||
"com_ui_marketplace_allow_use": "Allow using Marketplace",
|
"com_ui_marketplace_allow_use": "Allow using Marketplace",
|
||||||
"com_ui_marketplace_admin_settings": "Marketplace Admin Settings",
|
|
||||||
"com_ui_marketplace_admin_settings_description": "Configure which roles can access the Agent Marketplace.",
|
|
||||||
"com_ui_all": "all",
|
"com_ui_all": "all",
|
||||||
"com_ui_all_proper": "All",
|
"com_ui_all_proper": "All",
|
||||||
"com_ui_analyzing": "Analyzing",
|
"com_ui_analyzing": "Analyzing",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue