Unify auth context → role permission config resolution into a single pure utility (#18927)
## Summary - Consolidates duplicated auth-context-to-role-ID resolution logic (previously in `PermissionsService.resolveRolePermissionConfigFromAuthContext` and `CommonBaseQueryRunnerService.getRoleIdOrThrow`) into a single pure utility function `resolveRolePermissionConfig` in the ORM layer - The utility is synchronous and operates on cached data (`userWorkspaceRoleMap`, `apiKeyRoleMap`) already loaded into the workspace context — no async calls, no service dependencies - Adds `apiKeyRoleMap` to `ORMWorkspaceContext` (it was already in the workspace cache, just not loaded into the ORM context) - Removes `PermissionsService` dependency from `NavigationMenuItemRecordIdentifierService` - Removes `UserRoleService` and `ApiKeyRoleService` injections from `CommonBaseQueryRunnerService` ## Test plan - [ ] Existing typecheck passes (`npx nx typecheck twenty-server`) - [ ] Verify record identifier resolution still works for navigation menu items (user, system, API key, and application auth contexts) - [ ] Verify GraphQL CRUD queries still enforce correct role-based permissions - [ ] Verify API key authenticated requests resolve permissions correctly Made with [Cursor](https://cursor.com)
This commit is contained in:
+14
-8
@@ -10,9 +10,10 @@ import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadat
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { RecordIdentifierDTO } from 'src/engine/metadata-modules/navigation-menu-item/dtos/record-identifier.dto';
|
||||
import { getMinimalSelectForRecordIdentifier } from 'src/engine/metadata-modules/navigation-menu-item/utils/get-minimal-select-for-record-identifier.util';
|
||||
import { PermissionsService } from 'src/engine/metadata-modules/permissions/permissions.service';
|
||||
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
|
||||
import { getWorkspaceContext } from 'src/engine/twenty-orm/storage/orm-workspace-context.storage';
|
||||
import { formatResult } from 'src/engine/twenty-orm/utils/format-result.util';
|
||||
import { resolveRolePermissionConfig } from 'src/engine/twenty-orm/utils/resolve-role-permission-config.util';
|
||||
|
||||
@Injectable()
|
||||
export class NavigationMenuItemRecordIdentifierService {
|
||||
@@ -20,7 +21,6 @@ export class NavigationMenuItemRecordIdentifierService {
|
||||
private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
|
||||
private readonly fileService: FileService,
|
||||
private readonly permissionsService: PermissionsService,
|
||||
) {}
|
||||
|
||||
async resolveRecordIdentifier({
|
||||
@@ -63,18 +63,24 @@ export class NavigationMenuItemRecordIdentifierService {
|
||||
workspace: { id: workspaceId },
|
||||
} as WorkspaceAuthContext);
|
||||
|
||||
const rolePermissionConfig =
|
||||
await this.permissionsService.resolveRolePermissionConfigFromAuthContext(
|
||||
resolvedAuthContext,
|
||||
);
|
||||
|
||||
const record =
|
||||
await this.globalWorkspaceOrmManager.executeInWorkspaceContext(
|
||||
async () => {
|
||||
const context = getWorkspaceContext();
|
||||
const rolePermissionConfig = resolveRolePermissionConfig({
|
||||
authContext: context.authContext,
|
||||
userWorkspaceRoleMap: context.userWorkspaceRoleMap,
|
||||
apiKeyRoleMap: context.apiKeyRoleMap,
|
||||
});
|
||||
|
||||
if (!rolePermissionConfig) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const repository = await this.globalWorkspaceOrmManager.getRepository(
|
||||
workspaceId,
|
||||
objectMetadata.nameSingular,
|
||||
rolePermissionConfig ?? { shouldBypassPermissionChecks: true },
|
||||
rolePermissionConfig,
|
||||
);
|
||||
|
||||
const alias = objectMetadata.nameSingular;
|
||||
|
||||
@@ -13,10 +13,6 @@ import {
|
||||
ApplicationExceptionCode,
|
||||
} from 'src/engine/core-modules/application/application.exception';
|
||||
import { isApiKeyAuthContext } from 'src/engine/core-modules/auth/guards/is-api-key-auth-context.guard';
|
||||
import { isApplicationAuthContext } from 'src/engine/core-modules/auth/guards/is-application-auth-context.guard';
|
||||
import { isSystemAuthContext } from 'src/engine/core-modules/auth/guards/is-system-auth-context.guard';
|
||||
import { isUserAuthContext } from 'src/engine/core-modules/auth/guards/is-user-auth-context.guard';
|
||||
import { type WorkspaceAuthContext } from 'src/engine/core-modules/auth/types/workspace-auth-context.type';
|
||||
import { TOOL_PERMISSION_FLAGS } from 'src/engine/metadata-modules/permissions/constants/tool-permission-flags';
|
||||
import {
|
||||
PermissionsException,
|
||||
@@ -134,48 +130,6 @@ export class PermissionsService {
|
||||
objectsPermissions: {},
|
||||
}) as const satisfies UserWorkspacePermissions;
|
||||
|
||||
// TODO: this could likely be handled in the ORM layer
|
||||
public async resolveRolePermissionConfigFromAuthContext(
|
||||
authContext: WorkspaceAuthContext,
|
||||
): Promise<RolePermissionConfig | null> {
|
||||
const workspaceId = authContext.workspace.id;
|
||||
|
||||
if (isSystemAuthContext(authContext)) {
|
||||
return { shouldBypassPermissionChecks: true };
|
||||
}
|
||||
|
||||
if (isApiKeyAuthContext(authContext)) {
|
||||
const roleId = await this.apiKeyRoleService.getRoleIdForApiKeyId(
|
||||
authContext.apiKey.id,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
return { intersectionOf: [roleId] };
|
||||
}
|
||||
|
||||
if (
|
||||
isApplicationAuthContext(authContext) &&
|
||||
isDefined(authContext.application.defaultRoleId)
|
||||
) {
|
||||
return { intersectionOf: [authContext.application.defaultRoleId] };
|
||||
}
|
||||
|
||||
if (isUserAuthContext(authContext)) {
|
||||
const roleId = await this.userRoleService.getRoleIdForUserWorkspace({
|
||||
userWorkspaceId: authContext.userWorkspaceId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
if (!isDefined(roleId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return { intersectionOf: [roleId] };
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async userHasWorkspaceSettingPermission({
|
||||
userWorkspaceId,
|
||||
workspaceId,
|
||||
|
||||
Reference in New Issue
Block a user