🗞️ refactor: Apply Role Permissions at Startup only if Missing or Configured

This commit is contained in:
Danny Avila 2025-08-10 21:42:54 -04:00
parent d07c2b3475
commit 53c31b85d0
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
7 changed files with 355 additions and 440 deletions

View file

@ -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 };

View file

@ -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(),
})); }));

View file

@ -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(),

View file

@ -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,55 +133,35 @@ 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, [PermissionTypes.PROMPTS]: { [Permissions.USE]: loadedInterface.prompts },
[Permissions.OPT_OUT]: isPersonalizationEnabled, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks },
}, [PermissionTypes.MEMORIES]: {
[PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: loadedInterface.multiConvo }, [Permissions.USE]: loadedInterface.memories,
[PermissionTypes.AGENTS]: { [Permissions.USE]: loadedInterface.agents }, [Permissions.OPT_OUT]: isPersonalizationEnabled,
[PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: loadedInterface.temporaryChat }, },
[PermissionTypes.RUN_CODE]: { [Permissions.USE]: loadedInterface.runCode }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: loadedInterface.multiConvo },
[PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: loadedInterface.webSearch }, [PermissionTypes.AGENTS]: { [Permissions.USE]: loadedInterface.agents },
[PermissionTypes.PEOPLE_PICKER]: { [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: loadedInterface.temporaryChat },
[Permissions.VIEW_USERS]: [PermissionTypes.RUN_CODE]: { [Permissions.USE]: loadedInterface.runCode },
roleName === SystemRoles.USER ? false : loadedInterface.peoplePicker?.users, [PermissionTypes.WEB_SEARCH]: { [Permissions.USE]: loadedInterface.webSearch },
[Permissions.VIEW_GROUPS]: [PermissionTypes.PEOPLE_PICKER]: {
roleName === SystemRoles.USER ? false : loadedInterface.peoplePicker?.groups, [Permissions.VIEW_USERS]: loadedInterface.peoplePicker?.users,
[Permissions.VIEW_ROLES]: [Permissions.VIEW_GROUPS]: loadedInterface.peoplePicker?.groups,
roleName === SystemRoles.USER ? false : loadedInterface.peoplePicker?.roles, [Permissions.VIEW_ROLES]: loadedInterface.peoplePicker?.roles,
}, },
[PermissionTypes.MARKETPLACE]: { [PermissionTypes.MARKETPLACE]: {
[Permissions.USE]: roleName === SystemRoles.USER ? false : loadedInterface.marketplace?.use, [Permissions.USE]: loadedInterface.marketplace?.use,
}, },
[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 },
}); },
await updateAccessPermissions(SystemRoles.ADMIN, { interfaceConfig,
[PermissionTypes.PROMPTS]: { [Permissions.USE]: loadedInterface.prompts }, });
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks }, }
[PermissionTypes.MEMORIES]: {
[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]: loadedInterface.peoplePicker?.users,
[Permissions.VIEW_GROUPS]: loadedInterface.peoplePicker?.groups,
[Permissions.VIEW_ROLES]: loadedInterface.peoplePicker?.roles,
},
[PermissionTypes.MARKETPLACE]: {
[Permissions.USE]: loadedInterface.marketplace?.use,
},
[PermissionTypes.FILE_SEARCH]: { [Permissions.USE]: loadedInterface.fileSearch },
[PermissionTypes.FILE_CITATIONS]: { [Permissions.USE]: loadedInterface.fileCitations },
});
let i = 0; let i = 0;
const logSettings = () => { const logSettings = () => {

View file

@ -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 call updateAccessPermissions with true when config is undefined', async () => { 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 },
},
});
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 },
}); };
expect(updateAccessPermissions).toHaveBeenCalledTimes(2);
expect(updateAccessPermissions).toHaveBeenCalledWith(
SystemRoles.USER,
expectedPermissions,
expect.objectContaining({
permissions: {
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
},
}),
);
expect(updateAccessPermissions).toHaveBeenCalledWith(
SystemRoles.ADMIN,
expectedPermissions,
expect.objectContaining({
permissions: {
[PermissionTypes.PROMPTS]: { [Permissions.USE]: false },
[PermissionTypes.AGENTS]: { [Permissions.USE]: true },
},
}),
);
}); });
it('should call updateAccessPermissions with the correct parameters when multiConvo is true', async () => { it('should override existing permissions when explicitly configured', async () => {
const config = { interface: { multiConvo: true } }; // 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]: true },
[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 false when multiConvo is false', async () => {
const config = { interface: { multiConvo: 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]: 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 },
});
}); });
}); });

View file

@ -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

View file

@ -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",