From c0b8782f827c6dc01ff78ff9856e16c24b0d7b80 Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 14 May 2020 12:47:25 +0200 Subject: [PATCH 1/3] fix action permission as a function ( in resolver ) ; add typings --- src/engine/helpers.ts | 6 +- src/engine/permission/Permission.ts | 45 ++++--- .../ProtocolGraphQLConfiguration.ts | 110 +++++++++++------- src/graphqlProtocol/action.ts | 8 +- src/graphqlProtocol/helper.ts | 11 +- 5 files changed, 114 insertions(+), 66 deletions(-) diff --git a/src/engine/helpers.ts b/src/engine/helpers.ts index 2d110bf6..9a4fec21 100644 --- a/src/engine/helpers.ts +++ b/src/engine/helpers.ts @@ -1,10 +1,10 @@ import * as _ from 'lodash'; -import { Entity } from '..'; +import { Entity, Subscription } from '..'; import { Mutation } from './mutation/Mutation'; export const fillSystemAttributesDefaultValues = ( entity: Entity, - entityMutation: Mutation, + operation: Mutation | Subscription, payload: any, context: Record, ): any => { @@ -22,7 +22,7 @@ export const fillSystemAttributesDefaultValues = ( const attributeName = attribute.name; const defaultValue = attribute.defaultValue; - const value = defaultValue(ret, entityMutation, entity, context); + const value = defaultValue(ret, operation, entity, context); if (typeof value !== 'undefined') { ret[attributeName] = value; } diff --git a/src/engine/permission/Permission.ts b/src/engine/permission/Permission.ts index 85139387..7c298a5d 100644 --- a/src/engine/permission/Permission.ts +++ b/src/engine/permission/Permission.ts @@ -499,8 +499,6 @@ export const buildUserAttributesPermissionFilter = ({ if (permission.userAttributes.length > 0) { passOrThrow(userId, () => 'missing userId in permission object'); where = {}; - // where = where || {}; - // where.$or = where.$or || []; permission.userAttributes.map(attributeName => { const userAttrFilter = { @@ -533,8 +531,6 @@ export const buildStatesPermissionFilter = ({ if (permission.states.length > 0) { passOrThrow(entity, () => 'missing entity in permission object'); where = {}; - // where = where || {}; - // where.$or = where.$or || []; const states = entity.getStates(); const stateIds = permission.states.map(stateName => { @@ -573,8 +569,6 @@ export const buildValuesPermissionFilter = ({ if (permission.values.length > 0) { where = {}; - // where = where || {}; - // where.$or = where.$or || []; permission.values.map(({ attributeName, value }) => { const filter = { @@ -625,8 +619,6 @@ export const buildLookupsPermissionFilter = async ({ if (permission.lookups.length > 0) { where = {}; - // where = where || {}; - // where.$or = where.$or || []; await Promise.all( permission.lookups.map(async ({ entity, lookupMap }) => { @@ -812,10 +804,11 @@ export type ActionPermissionFilter = { }; export const buildActionPermissionFilter = async ( - _permissions: Permission | Permission[], + _permissions: Function | Permission | Permission[], userId = null, userRoles = [], - action: Action, + action: Action | Subscription, + // action: Action, input?: any, context?: any, ): Promise< @@ -829,10 +822,22 @@ export const buildActionPermissionFilter = async ( return undefined; } - // const permissions = isArray(_permissions) ? _permissions : [_permissions]; - const permissions = isArray(_permissions as Permission[]) - ? (_permissions as Permission[]) - : ([_permissions] as Permission[]); + let permissions: Permission[]; + if (isFunction(_permissions)) { + const permissionFn = _permissions as Function; + const permissionResult = permissionFn(); + permissions = isArray(permissionResult) + ? permissionResult + : [permissionResult]; + } else if (isArray(_permissions as Permission[])) { + permissions = _permissions as Permission[]; + } else { + permissions = [_permissions] as Permission[]; + } + + // const permissions = isArray(_permissions as Permission[]) + // ? (_permissions as Permission[]) + // : ([_permissions] as Permission[]); let foundSimplePermission = false; @@ -1036,6 +1041,18 @@ export const findEmptyEntityPermissions = (permissions): string[] => { }); } + if (permissions.subscriptions) { + const subscriptionNames = Object.keys(permissions.subscriptions); + subscriptionNames.map(subscriptionName => { + if ( + permissions.subscriptions[subscriptionName] && + hasEmptyPermissions(permissions.subscriptions[subscriptionName]) + ) { + emptyPermissionsIn.push(`subscriptions.${subscriptionName}`); + } + }); + } + return emptyPermissionsIn; }; diff --git a/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts index d9faf201..e3025971 100644 --- a/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts +++ b/src/graphqlProtocol/ProtocolGraphQLConfiguration.ts @@ -7,7 +7,7 @@ import { } from './util'; import { MAX_PAGE_SIZE } from './protocolGraphqlConstants'; import { ProtocolConfiguration } from '../engine/protocol/ProtocolConfiguration'; -import { Mutation, Subscription, Entity } from '..'; +import { Mutation, Subscription, Entity, Action, ViewEntity } from '..'; export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { constructor() { @@ -35,33 +35,39 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { /* name generators */ - generateEntityTypeName(entity) { + generateEntityTypeName(entity: Entity | ViewEntity): string { return generateTypeName(entity.name); } - generateEntityTypeNamePlural(entity) { + generateEntityTypeNamePlural(entity: Entity | ViewEntity): string { return generateTypeNamePlural(entity.name); } - generateEntityTypeNamePascalCase(entity) { + generateEntityTypeNamePascalCase(entity: Entity | ViewEntity): string { return generateTypeNamePascalCase(entity.name); } - generateEntityTypeNamePluralPascalCase(entity) { + generateEntityTypeNamePluralPascalCase(entity: Entity | ViewEntity): string { return generateTypeNamePluralPascalCase(entity.name); } - generateReverseConnectionFieldName(sourceEntity, sourceAttributeName) { + generateReverseConnectionFieldName( + sourceEntity: Entity | ViewEntity, + sourceAttributeName, + ): string { const typeNamePlural = this.generateEntityTypeNamePlural(sourceEntity); return generateTypeName(`${typeNamePlural}-by-${sourceAttributeName}`); } - generateReferenceFieldName(referenceEntity, attribute) { + generateReferenceFieldName( + referenceEntity: Entity | ViewEntity, + attribute, + ): string { const fieldName = this.generateFieldName(attribute); return generateTypeName(`${referenceEntity.name}-by-${fieldName}`); } - generateReferenceFieldListName(referenceEntity, attribute) { + generateReferenceFieldListName(referenceEntity, attribute): string { const fieldName = this.generateFieldName(attribute); const referenceEntityNamePlural = this.generateEntityTypeNamePlural( referenceEntity, @@ -69,72 +75,85 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { return generateTypeName(`${referenceEntityNamePlural}-by-${fieldName}`); } - generateFieldName(attribute) { + generateFieldName(attribute): string { return generateTypeName(attribute.name); } - generateI18nJsonFieldName(attribute) { + generateI18nJsonFieldName(attribute): string { const fieldName = this.generateFieldName(attribute); return `${fieldName}_i18nJson`; } - generateI18nFieldName(attribute) { + generateI18nFieldName(attribute): string { const fieldName = this.generateFieldName(attribute); return `${fieldName}_i18n`; } - generateI18nFieldTypeName(entity, attribute) { + generateI18nFieldTypeName(entity: Entity | ViewEntity, attribute) { const typeName = this.generateEntityTypeName(entity); const fieldName = this.generateFieldName(attribute); return generateTypeNamePascalCase(`${typeName}-${fieldName}-i18n`); } - generateListQueryTypeName(entity) { + generateListQueryTypeName(entity: Entity | ViewEntity) { const typeNamePlural = this.generateEntityTypeNamePlural(entity); return generateTypeName(`all-${typeNamePlural}`); } - generateInstanceQueryTypeName(entity) { + generateInstanceQueryTypeName(entity: Entity | ViewEntity): string { return this.generateEntityTypeName(entity); } - generateInstanceByUniqueQueryTypeName(entity, attribute) { + generateInstanceByUniqueQueryTypeName( + entity: Entity | ViewEntity, + attribute, + ): string { const typeName = this.generateEntityTypeName(entity); const fieldName = this.generateFieldName(attribute); return generateTypeName(`${typeName}-by-${fieldName}`); } - generateUniquenessAttributesName(_entity, attributes) { + generateUniquenessAttributesName( + _entity: Entity | ViewEntity, + attributes, + ): string { return generateTypeName(attributes.join('-and-')); } generateUniquenessAttributesFieldName( - _entity, + _entity: Entity | ViewEntity, attribute, - uniquenessAttributesName, - ) { + uniquenessAttributesName: string, + ): string { const fieldName = this.generateFieldName(attribute); return generateTypeName( `${fieldName}-by-unique-${uniquenessAttributesName}`, ); } - generateInstanceUniquenessInputTypeName(entity, uniquenessAttributesName) { + generateInstanceUniquenessInputTypeName( + entity: Entity | ViewEntity, + uniquenessAttributesName, + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase( `${typeName}-instance-uniqueness-on-${uniquenessAttributesName}-input`, ); } - generateActionTypeName(action) { + generateActionTypeName(action: Action): string { return generateTypeName(action.name); } - generateDataInputTypeName(baseName) { + generateDataInputTypeName(baseName: string): string { return generateTypeNamePascalCase(`${baseName}-data-input`); } - generateNestedDataInputTypeName(baseName, nestedParamName, level) { + generateNestedDataInputTypeName( + baseName: string, + nestedParamName: string, + level: number, + ): string { const levelStr = level > 1 ? `L${level}` : ''; return generateTypeNamePascalCase( @@ -142,11 +161,11 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateInputTypeName(baseName: string) { + generateInputTypeName(baseName: string): string { return generateTypeNamePascalCase(`${baseName}-input`); } - generateDataOutPutTypeName(baseName: string) { + generateDataOutPutTypeName(baseName: string): string { return generateTypeNamePascalCase(`${baseName}-data-output`); } @@ -154,7 +173,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { baseName: string, nestedParamName: string, level?: number, - ) { + ): string { const levelStr = level > 1 ? `L${level}` : ''; return generateTypeNamePascalCase( @@ -162,44 +181,47 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { ); } - generateOutPutTypeName(baseName: string) { + generateOutPutTypeName(baseName: string): string { return generateTypeNamePascalCase(`${baseName}-output`); } - generateSortKeyName(attribute: any, ascending?: boolean) { + generateSortKeyName(attribute: any, ascending?: boolean): string { const direction = ascending ? 'ASC' : 'DESC'; return `${generateTypeNameUpperCase(attribute.name)}_${direction}`; } - generateSortInputTypeName(entity) { + generateSortInputTypeName(entity: Entity | ViewEntity): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${typeName}-order-by`); } - generateFilterInputTypeName(entity) { + generateFilterInputTypeName(entity: Entity | ViewEntity): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${typeName}-filter`); } - generateFilterPreFilterInputTypeName(entity) { + generateFilterPreFilterInputTypeName(entity: Entity | ViewEntity): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${typeName}-pre-filter`); } - generateFilterPreFilterParamsInputTypeName(entity, preFilter) { + generateFilterPreFilterParamsInputTypeName( + entity: Entity | ViewEntity, + preFilter, + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase( `${typeName}-pre-filter-${preFilter}-params`, ); } - generateConnectionEdgeTypeName(entity) { + generateConnectionEdgeTypeName(entity: Entity | ViewEntity): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${typeName}-edge`); } - generateConnectionTypeName(entity): string { + generateConnectionTypeName(entity: Entity | ViewEntity): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${typeName}-connection`); } @@ -208,7 +230,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { entity: Entity | any, operation: Mutation | Subscription | any, attribute, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); const fieldName = this.generateFieldName(attribute); return generateTypeNamePascalCase( @@ -219,7 +241,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { generateOperationInstanceInputTypeName( entity: Entity, operation: Mutation | Subscription, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase( `${operation.name}-${typeName}-instance-input`, @@ -229,7 +251,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { generateOperationInputTypeName( entity: Entity, operation: Mutation | Subscription, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${operation.name}-${typeName}-input`); } @@ -238,7 +260,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { entity: Entity, operation: Mutation | Subscription, attribute, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); const fieldName = this.generateFieldName(attribute); return generateTypeNamePascalCase( @@ -249,7 +271,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { generateOperationInstanceNestedInputTypeName( entity: Entity, operation: Mutation | Subscription, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase( `${operation.name}-${typeName}-instance-nested-input`, @@ -259,7 +281,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { generateOperationNestedInputTypeName( entity: Entity, operation: Mutation | Subscription, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase( `${operation.name}-${typeName}-nested-input`, @@ -269,7 +291,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { generateOperationOutputTypeName( entity: Entity, operation: Mutation | Subscription, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeNamePascalCase(`${operation.name}-${typeName}-output`); } @@ -277,7 +299,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { generateOperationTypeName( entity: Entity, operation: Mutation | Subscription, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeName(`${operation.name}-${typeName}`); } @@ -285,7 +307,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { generateOperationNestedTypeName( entity: Entity, operation: Mutation | Subscription, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); return generateTypeName(`${operation.name}-${typeName}-nested`); } @@ -294,7 +316,7 @@ export class ProtocolGraphQLConfiguration extends ProtocolConfiguration { entity: Entity, operation: Mutation | Subscription, attribute, - ) { + ): string { const typeName = this.generateEntityTypeName(entity); const fieldName = this.generateFieldName(attribute); return generateTypeName(`${operation.name}-${typeName}-by-${fieldName}`); diff --git a/src/graphqlProtocol/action.ts b/src/graphqlProtocol/action.ts index 3ff361fd..e9d33a85 100644 --- a/src/graphqlProtocol/action.ts +++ b/src/graphqlProtocol/action.ts @@ -13,7 +13,7 @@ import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { isObjectDataType } from '../engine/datatype/ObjectDataType'; import { isListDataType } from '../engine/datatype/ListDataType'; import { validateActionPayload } from '../engine/validation'; -import { ACTION_TYPE_MUTATION } from '../engine/action/Action'; +import { ACTION_TYPE_MUTATION, Action } from '../engine/action/Action'; import { buildActionPermissionFilter } from '../engine/permission/Permission'; import { CustomError } from '../engine/CustomError'; @@ -80,7 +80,11 @@ const fillNestedDefaultValues = async (params, payload, context) => { const fillDefaultValues = async (param, payload, context) => fillSingleDefaultValues(param, payload, context); -export const handlePermission = async (context, action, input) => { +export const handlePermission = async ( + context: any, + action: Action, + input: any, +) => { const permission = action.getPermissions(); if (!permission) { diff --git a/src/graphqlProtocol/helper.ts b/src/graphqlProtocol/helper.ts index 4689cb9d..b418da18 100644 --- a/src/graphqlProtocol/helper.ts +++ b/src/graphqlProtocol/helper.ts @@ -4,6 +4,7 @@ import { ProtocolGraphQLConfiguration } from './ProtocolGraphQLConfiguration'; import { INDEX_UNIQUE } from '../engine/index/Index'; import { CustomError } from '../engine/CustomError'; +import { Entity, Mutation, Subscription } from '..'; export const getEntityUniquenessAttributes = entity => { const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; @@ -33,10 +34,14 @@ export const getEntityUniquenessAttributes = entity => { return ret; }; -export const checkRequiredI18nInputs = (entity, entityMutation, input) => { +export const checkRequiredI18nInputs = ( + entity: Entity | any, + operation: Mutation | Subscription, + input: any, +) => { const entityAttributes = entity.getAttributes(); - _.forEach(entityMutation.attributes, attributeName => { + _.forEach(operation.attributes, attributeName => { const attribute = entityAttributes[attributeName]; const { gqlFieldName, gqlFieldNameI18n } = attribute; @@ -52,7 +57,7 @@ export const checkRequiredI18nInputs = (entity, entityMutation, input) => { ); } - if (attribute.required && !entityMutation.ignoreRequired) { + if (attribute.required && !operation.ignoreRequired) { if (!input[gqlFieldName] && !input[gqlFieldNameI18n]) { throw new CustomError( `Provide one of these fields: ${gqlFieldName}, ${gqlFieldNameI18n}`, From e0f1fc88bc8637b973c0d09939f86736e91d8789 Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 14 May 2020 12:48:07 +0200 Subject: [PATCH 2/3] Change topic composition in getSubscriptionResolver ( forced prefix ) and fix Subscription test --- src/engine/subscription/Subscription.spec.ts | 3 +- src/graphqlProtocol/resolver.ts | 141 ++++++++++++++----- 2 files changed, 106 insertions(+), 38 deletions(-) diff --git a/src/engine/subscription/Subscription.spec.ts b/src/engine/subscription/Subscription.spec.ts index 0bb10351..818f1eb8 100644 --- a/src/engine/subscription/Subscription.spec.ts +++ b/src/engine/subscription/Subscription.spec.ts @@ -375,8 +375,7 @@ describe('Subscription', () => { .map(attribute => input[attribute]) .reduce((acc, curr) => `${acc + delimiter + curr}`, ''); - const topic = `${entitySubscription.name}${_entity.name}${filled}`; - return topic; + return filled; } return null; diff --git a/src/graphqlProtocol/resolver.ts b/src/graphqlProtocol/resolver.ts index ce323d4b..44f8ccbe 100644 --- a/src/graphqlProtocol/resolver.ts +++ b/src/graphqlProtocol/resolver.ts @@ -22,17 +22,19 @@ import { getEntityUniquenessAttributes, checkRequiredI18nInputs, } from './helper'; -import { isEntity } from '../engine/entity/Entity'; +import { isEntity, Entity } from '../engine/entity/Entity'; import { MUTATION_TYPE_CREATE, MUTATION_TYPE_UPDATE, MUTATION_TYPE_DELETE, + Mutation, } from '../engine/mutation/Mutation'; import { SUBSCRIPTION_TYPE_CREATE, SUBSCRIPTION_TYPE_UPDATE, // SUBSCRIPTION_TYPE_DELETE, pubsub, + Subscription, } from '../engine/subscription/Subscription'; import { CustomError } from '../engine/CustomError'; import { @@ -41,6 +43,13 @@ import { serializeValues, } from '../engine/helpers'; import { validateMutationPayload } from '../engine/validation'; +import { buildActionPermissionFilter } from '../engine/permission/Permission'; + +const AccessDeniedError = new CustomError( + 'Access denied', + 'PermissionError', + 403, +); export const resolveByFind = (entity, parentConnectionCollector?: any) => { const storageType = entity.storageType; @@ -297,11 +306,11 @@ export const getNestedPayloadResolver = ( }; export const getMutationResolver = ( - entity, - entityMutation, - typeName, - nested, - idResolver, + entity: Entity | any, + entityMutation: Mutation, + typeName: string, + nested: boolean, + idResolver: Function, ) => { const storageType = entity.storageType; const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; @@ -458,12 +467,78 @@ export const getMutationResolver = ( }; }; +export const handleSubscriptionPermission = async ( + context: any, + entity: Entity, + entitySubscription: Subscription, + input: any, +) => { + const permission = entity.getPermissions(); + + console.log('handleSubscriptionPermission', { permission }); + + if (!permission) { + return null; + } + + const subPermission = permission.subscriptions; + if (!subPermission) { + return null; + } + + const { userId, userRoles } = context; + + console.log('handleSubscriptionPermission', { subPermission }); + + const { + where: permissionWhere, + lookupPermissionEntity, + } = await buildActionPermissionFilter( + subPermission, + userId, + userRoles, + entitySubscription, + input, + context, + ); + + if (!permissionWhere) { + throw AccessDeniedError; + } + + console.log('handleSubscriptionPermission', { + permissionWhere, + lookupPermissionEntity, + }); + + // only if non-empty where clause + if (Object.keys(permissionWhere).length > 0) { + const storageType = lookupPermissionEntity.getStorageType(); + const found = await storageType.checkLookupPermission( + lookupPermissionEntity, + permissionWhere, + context, + ); + + if (!found) { + throw AccessDeniedError; + } + } + + return permissionWhere; +}; + +export const setTopicEnd = (entitySubscription: Subscription): string => + entitySubscription.wildCard + ? entitySubscription.delimiter + entitySubscription.wildCard + : ''; + export const getSubscriptionResolver = ( - entity, - entitySubscription, - typeName, - nested, - idResolver, + entity: Entity, + entitySubscription: Subscription, + typeName: string, + nested: boolean, + idResolver: Function, ) => { const storageType = entity.storageType; // const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; @@ -487,6 +562,13 @@ export const getSubscriptionResolver = ( // context, ); + await handleSubscriptionPermission( + context, + entity, + entitySubscription, + args.input[typeName], + ); + if (nested) { args.input[typeName] = await nestedPayloadResolver( source, @@ -530,30 +612,21 @@ export const getSubscriptionResolver = ( // ); // } - let topic; + let extraTopic: string; const delimiter = entitySubscription.delimiter; - if (entitySubscription.pattern) { - // const delimiter = entitySubscription.delimiter; - // const filled = entitySubscription.attributes - // .map(attribute => input[attribute]) - // .reduce((acc, curr) => `${acc + delimiter + curr}`, ''); + const baseTopic = `${entitySubscription.name}${entity.name}`; + if (entitySubscription.pattern) { const params = entitySubscription.pattern .split(delimiter) .reduce((acc, curr) => (acc[curr] = args.input[typeName][curr]), {}); - console.log('getSubscriptionResolver', { params }); + // console.log('getSubscriptionResolver', { params }); const filled = Object.values(params).join(delimiter); - - console.log('getSubscriptionResolver', { filled }); - - topic = `${entitySubscription.name}${entity.name}/${filled}${ - entitySubscription.wildCard - ? delimiter + entitySubscription.wildCard - : '' - }`; + // console.log('getSubscriptionResolver', { filled }); + extraTopic = `${delimiter}${filled}${setTopicEnd(entitySubscription)}`; } else if (entitySubscription.preProcessor) { - topic = await entitySubscription.preProcessor( + extraTopic = await entitySubscription.preProcessor( entity, id, source, @@ -564,15 +637,11 @@ export const getSubscriptionResolver = ( info, ); } - if (!topic) { - topic = `${entitySubscription.name}${entity.name}${ - entitySubscription.wildCard - ? delimiter + entitySubscription.wildCard - : '' - }`; + if (!extraTopic) { + extraTopic = setTopicEnd(entitySubscription); } - // console.log('getSubscriptionResolver', { topic }); + const topic = `${baseTopic}${extraTopic}`; return context.pubsub ? context.pubsub.asyncIterator(topic) @@ -581,8 +650,8 @@ export const getSubscriptionResolver = ( }; export const getSubscriptionPayloadResolver = ( - entity, - entitySubscription, + entity: Entity, + entitySubscription: Subscription, typeName, ) => { return async (source, args, context, info) => { From 384167c659c4df4ae653bfdab24e755acce5ea20 Mon Sep 17 00:00:00 2001 From: getlarge Date: Thu, 14 May 2020 13:37:15 +0200 Subject: [PATCH 3/3] Fix subscription permission handling --- src/engine/action/Action.ts | 4 ++-- src/graphqlProtocol/resolver.ts | 38 ++++++++++++++++----------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/engine/action/Action.ts b/src/engine/action/Action.ts index f9c6d081..3d2e6072 100644 --- a/src/engine/action/Action.ts +++ b/src/engine/action/Action.ts @@ -56,7 +56,7 @@ export class Action { private _output: any; resolve: Function; type: string; - permissions: Function | Permission | Permission[]; + permissions: Permission | Permission[]; private _permissions: Function | Permission | Permission[]; private _defaultPermissions: Permission | Permission[]; descriptionPermissions: string | boolean; @@ -252,7 +252,7 @@ export class Action { this._defaultPermissions = defaultPermissions; } - getPermissions(): Function | Permission | Permission[] { + getPermissions(): Permission | Permission[] { if ((!this._permissions && !this._defaultPermissions) || this.permissions) { return this.permissions; } diff --git a/src/graphqlProtocol/resolver.ts b/src/graphqlProtocol/resolver.ts index 44f8ccbe..bf1c40f0 100644 --- a/src/graphqlProtocol/resolver.ts +++ b/src/graphqlProtocol/resolver.ts @@ -43,7 +43,10 @@ import { serializeValues, } from '../engine/helpers'; import { validateMutationPayload } from '../engine/validation'; -import { buildActionPermissionFilter } from '../engine/permission/Permission'; +import { + buildActionPermissionFilter, + Permission, +} from '../engine/permission/Permission'; const AccessDeniedError = new CustomError( 'Access denied', @@ -473,28 +476,26 @@ export const handleSubscriptionPermission = async ( entitySubscription: Subscription, input: any, ) => { - const permission = entity.getPermissions(); - - console.log('handleSubscriptionPermission', { permission }); - - if (!permission) { + const permissionsMap = entity.getPermissions(); + if ( + !permissionsMap || + !permissionsMap.subscriptions || + !Object.keys(permissionsMap.subscriptions).length + ) { return null; } - const subPermission = permission.subscriptions; - if (!subPermission) { - return null; - } + const subPermissions = ([] as Permission[]).concat( + ...Object.values(permissionsMap.subscriptions as Permission | Permission[]), + ); const { userId, userRoles } = context; - console.log('handleSubscriptionPermission', { subPermission }); - const { where: permissionWhere, lookupPermissionEntity, } = await buildActionPermissionFilter( - subPermission, + subPermissions, userId, userRoles, entitySubscription, @@ -506,10 +507,10 @@ export const handleSubscriptionPermission = async ( throw AccessDeniedError; } - console.log('handleSubscriptionPermission', { - permissionWhere, - lookupPermissionEntity, - }); + // console.log('handleSubscriptionPermission', { + // permissionWhere, + // lookupPermissionEntity, + // }); // only if non-empty where clause if (Object.keys(permissionWhere).length > 0) { @@ -541,7 +542,6 @@ export const getSubscriptionResolver = ( idResolver: Function, ) => { const storageType = entity.storageType; - // const protocolConfiguration = ProtocolGraphQL.getProtocolConfiguration() as ProtocolGraphQLConfiguration; const nestedPayloadResolver = getNestedPayloadResolver( entity, @@ -688,8 +688,6 @@ export const getSubscriptionPayloadResolver = ( ret[typeName] = result; } - // console.log('getSubscriptionPayloadResolver', JSON.stringify(ret, null, 2)); - return ret; }; };