From 2418e4d7f917988991d0044ab6cefe75b8b4ede8 Mon Sep 17 00:00:00 2001 From: Tomer Braufman Date: Mon, 21 Sep 2020 00:55:16 +0300 Subject: [PATCH 1/5] support context params binding --- src/main.ts | 46 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/src/main.ts b/src/main.ts index 34100e4..cf496be 100644 --- a/src/main.ts +++ b/src/main.ts @@ -20,9 +20,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -import { has, merge, random, get } from 'lodash'; +import { has, merge, random, get, forEach, split, indexOf } from 'lodash'; import { CloudFunction, EventContext, Change, https } from 'firebase-functions'; +import { QueryDocumentSnapshot } from 'firebase-functions/lib/providers/firestore'; /** Fields of the event context that can be overridden/customized. */ export type EventContextOptions = { @@ -153,7 +154,7 @@ export function wrap( ['eventId', 'timestamp', 'params', 'auth', 'authType', 'resource'], options ); - const defaultContext = _makeDefaultContext(cloudFunction, options); + const defaultContext = _makeDefaultContext(cloudFunction, options, data); if ( has(defaultContext, 'eventType') && @@ -186,6 +187,21 @@ export function _makeResourceName( return resourceName; } +function _makeDefaultParams(triggerResource, name) { + const wildcards = triggerResource.match(new RegExp('{[^/{}]*}', 'g')); + const params = {}; + if (wildcards) { + const triggerResourceParts = split(triggerResource, '/'); + const eventResourceParts = split(name, '/'); + forEach(wildcards, (wildcard) => { + const wildcardNoBraces = wildcard.slice(1, -1); + const position = indexOf(triggerResourceParts, wildcard); + params[wildcardNoBraces] = eventResourceParts[position]; + }); + } + return params; +} + function _makeEventId(): string { return ( Math.random() @@ -212,21 +228,29 @@ function _checkOptionValidity( function _makeDefaultContext( cloudFunction: CloudFunction, - options: ContextOptions + options: ContextOptions, + data?: T ): EventContext { let eventContextOptions = options as EventContextOptions; + const resource = cloudFunction.__trigger.eventTrigger && { + service: cloudFunction.__trigger.eventTrigger.service, + name: '' + }; + if(cloudFunction.__trigger.eventTrigger.service == "firestore.googleapis.com" && !has(eventContextOptions, 'params')) { + try { + cloudFunction.__trigger.eventTrigger.resource.substring(0, cloudFunction.__trigger.eventTrigger.resource.indexOf("documents")) + "documents/" + (data as unknown as QueryDocumentSnapshot).ref.path; + } catch(error) { + resource.name = _makeResourceName(cloudFunction.__trigger.eventTrigger.resource, has(eventContextOptions, 'params') && eventContextOptions.params); + } + } else { + resource.name = _makeResourceName(cloudFunction.__trigger.eventTrigger.resource, has(eventContextOptions, 'params') && eventContextOptions.params); + } const defaultContext: EventContext = { eventId: _makeEventId(), - resource: cloudFunction.__trigger.eventTrigger && { - service: cloudFunction.__trigger.eventTrigger.service, - name: _makeResourceName( - cloudFunction.__trigger.eventTrigger.resource, - has(eventContextOptions, 'params') && eventContextOptions.params - ), - }, + resource: resource, eventType: get(cloudFunction, '__trigger.eventTrigger.eventType'), timestamp: new Date().toISOString(), - params: {}, + params: _makeDefaultParams(cloudFunction.__trigger.eventTrigger.resource, resource.name), }; return defaultContext; } From 96d2c47b8edc83c0cb016033fb54d11bc1510ffd Mon Sep 17 00:00:00 2001 From: Tomer Braufman Date: Mon, 21 Sep 2020 01:06:38 +0300 Subject: [PATCH 2/5] test for not automatic binding on firestore event --- spec/main.spec.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spec/main.spec.ts b/spec/main.spec.ts index 9ff1cce..fe82a6c 100644 --- a/spec/main.spec.ts +++ b/spec/main.spec.ts @@ -74,6 +74,17 @@ describe('main', () => { expect(context.timestamp).to.equal('2018-03-28T18:58:50.370Z'); }); + it('should create context params and resource from contextOptions on firestore event', async () => { + const params = { + wildcard: 'a', + anotherWildcard: 'b', + }; + const wrapped = wrap(constructCF()); + const context = wrapped('data', { params }).context; + expect(context.params).to.deep.equal(params); + expect(context.resource.name).to.equal('ref/a/nested/b'); + }); + it('should generate auth and authType for database functions', () => { const context = wrap(constructCF('google.firebase.database.ref.write'))( 'data' From 7a3c0b41acb7642afac520c8811a4c9a9c0f053b Mon Sep 17 00:00:00 2001 From: Tomer Braufman Date: Mon, 21 Sep 2020 01:19:21 +0300 Subject: [PATCH 3/5] bind params only on docuement resource name --- src/main.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index cf496be..41dfa72 100644 --- a/src/main.ts +++ b/src/main.ts @@ -232,6 +232,7 @@ function _makeDefaultContext( data?: T ): EventContext { let eventContextOptions = options as EventContextOptions; + let isDocumentResourceName = false; const resource = cloudFunction.__trigger.eventTrigger && { service: cloudFunction.__trigger.eventTrigger.service, name: '' @@ -239,6 +240,7 @@ function _makeDefaultContext( if(cloudFunction.__trigger.eventTrigger.service == "firestore.googleapis.com" && !has(eventContextOptions, 'params')) { try { cloudFunction.__trigger.eventTrigger.resource.substring(0, cloudFunction.__trigger.eventTrigger.resource.indexOf("documents")) + "documents/" + (data as unknown as QueryDocumentSnapshot).ref.path; + isDocumentResourceName = true; } catch(error) { resource.name = _makeResourceName(cloudFunction.__trigger.eventTrigger.resource, has(eventContextOptions, 'params') && eventContextOptions.params); } @@ -250,7 +252,7 @@ function _makeDefaultContext( resource: resource, eventType: get(cloudFunction, '__trigger.eventTrigger.eventType'), timestamp: new Date().toISOString(), - params: _makeDefaultParams(cloudFunction.__trigger.eventTrigger.resource, resource.name), + params: isDocumentResourceName? _makeDefaultParams(cloudFunction.__trigger.eventTrigger.resource, resource.name) : {} }; return defaultContext; } From 228cfef7d6d06b8fe342ddff3523d333a1a628da Mon Sep 17 00:00:00 2001 From: Tomer Braufman Date: Mon, 21 Sep 2020 01:21:28 +0300 Subject: [PATCH 4/5] delete testing --- spec/main.spec.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/spec/main.spec.ts b/spec/main.spec.ts index fe82a6c..9ff1cce 100644 --- a/spec/main.spec.ts +++ b/spec/main.spec.ts @@ -74,17 +74,6 @@ describe('main', () => { expect(context.timestamp).to.equal('2018-03-28T18:58:50.370Z'); }); - it('should create context params and resource from contextOptions on firestore event', async () => { - const params = { - wildcard: 'a', - anotherWildcard: 'b', - }; - const wrapped = wrap(constructCF()); - const context = wrapped('data', { params }).context; - expect(context.params).to.deep.equal(params); - expect(context.resource.name).to.equal('ref/a/nested/b'); - }); - it('should generate auth and authType for database functions', () => { const context = wrap(constructCF('google.firebase.database.ref.write'))( 'data' From fc2dfc1a1d66e60cff0ca8d85e740b2b2ff6a0a3 Mon Sep 17 00:00:00 2001 From: Tomer Braufman Date: Mon, 21 Sep 2020 01:31:42 +0300 Subject: [PATCH 5/5] lint fix --- src/main.ts | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/main.ts b/src/main.ts index 41dfa72..34aa295 100644 --- a/src/main.ts +++ b/src/main.ts @@ -237,22 +237,30 @@ function _makeDefaultContext( service: cloudFunction.__trigger.eventTrigger.service, name: '' }; - if(cloudFunction.__trigger.eventTrigger.service == "firestore.googleapis.com" && !has(eventContextOptions, 'params')) { + if(cloudFunction.__trigger.eventTrigger.service === 'firestore.googleapis.com' + && !has(eventContextOptions, 'params')) { try { - cloudFunction.__trigger.eventTrigger.resource.substring(0, cloudFunction.__trigger.eventTrigger.resource.indexOf("documents")) + "documents/" + (data as unknown as QueryDocumentSnapshot).ref.path; + cloudFunction.__trigger.eventTrigger.resource.substring(0, cloudFunction.__trigger.eventTrigger.resource.indexOf('documents')) + + 'documents/' + + (data as unknown as QueryDocumentSnapshot).ref.path; isDocumentResourceName = true; } catch(error) { - resource.name = _makeResourceName(cloudFunction.__trigger.eventTrigger.resource, has(eventContextOptions, 'params') && eventContextOptions.params); + resource.name = _makeResourceName(cloudFunction.__trigger.eventTrigger.resource + , has(eventContextOptions, 'params') + && eventContextOptions.params); } } else { - resource.name = _makeResourceName(cloudFunction.__trigger.eventTrigger.resource, has(eventContextOptions, 'params') && eventContextOptions.params); + resource.name = _makeResourceName(cloudFunction.__trigger.eventTrigger.resource, has(eventContextOptions, 'params') + && eventContextOptions.params); } const defaultContext: EventContext = { eventId: _makeEventId(), - resource: resource, + resource, eventType: get(cloudFunction, '__trigger.eventTrigger.eventType'), timestamp: new Date().toISOString(), - params: isDocumentResourceName? _makeDefaultParams(cloudFunction.__trigger.eventTrigger.resource, resource.name) : {} + params: isDocumentResourceName + ? _makeDefaultParams(cloudFunction.__trigger.eventTrigger.resource, resource.name) + : {} }; return defaultContext; }